Java- Palindrome Program - java

I have been assigned to complete a palindrome program. However, I cannot use the charAt method.
Typically, I'd be able to solve this fairly quickly. However, since I cannot use charAt, I have no clue as to how I should go about doing this.
My idea is to take the length of the string, divide it by two (however this limits me to strings only with an even number of chars) then convert the substrings into int's and then finally compare the two int's.
This is my code thus far-
public static boolean isPal(String s)
{
int length = s.length();
int math = length / 2;
String side1 = s.substring(1,math);
String side2 = s.substring(math, length);
int s1 = Integer.parseInt(side1);
int s2 = Integer.parseInt(side2);
if(s1 == s2){
return true;
} else {
return false;
}
}
However, I have realized that this might not, and probably is not, the best way to handle the situation. I am currently running into this error-
Exception in thread "main" java.lang.NumberFormatException: For input string: "i"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at Palindrome.isPal(Lab08st.java:47)
at Lab08st.main(Lab08st.java:20)
I believe it is because I need a for loop of sorts.
However, having inadequate Java experience, I am unsure.
I am open to any and all suggestions. (So long as they do not require charAt)

Use this:
public static boolean isPal(String s) {
char[] chars = s.toCharArray();
int len = chars.length;
for (int i = 0; i < len ; i++) {
if(chars[i] != chars[len-i-1] ){
return false;
}
}
return true;
}

Your approach is flawed in several ways:
Integer.parseInt(String) only works on optionally-signed digit strings that represent base-10 numbers representable as type int. Your function will utterly fail on non-numeric inputs, and on inputs that are too large for the halves to be represented as ints (some 19-20-character inputs; all longer inputs).
Your function will fail on any input having an odd number of characters, because you cannot split such inputs evenly into halves.
Your logic is flawed anyway. It would judge "1010" a palindrome (which it isn't), and it would judge "1001" not a palindrome (though it is one).
You can pick out the input String's characters one-by-one via a variety of techniques, among them:
You can get the characters in a char[] via String.toCharArray(), as has elsewhere been suggested.
You can consume the input via a series of substring() invocations.
You can use a StringCharacterIterator to iterate over the characters
Since it's not clear why you are not permitted to use charAt(), here's an approach that altogether avoids relying on indexing:
import java.text.StringCharacterIterator;
// ...
public static boolean isPal(String s)
{
StringCharacterIterator it = new StringCharacterIterator(s);
String reversed = ""
for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
reversed = c + reversed;
}
return reversed.equals(s);
}
There are more efficient approaches, but that one is clear and simple.
Or here's one that doesn't rely (explicitly) on any classes other then String, but does use the indexes 0 and 1:
public static boolean isPal(String s)
{
String tail = s;
String reversed = ""
while (tail.length() > 0) {
reversed = tail.substring(0, 1) + reversed;
tail = tail.substring(1);
}
return reversed.equals(s);
}
Or since you had the idea of splitting the String into two, perhaps that was directed by your instructor? Are you perhaps studying recursion? Because you can also reverse the input string via a recursive algorithm: (1) split the string in two (as evenly as possible works best); (2) recursively reverse each half; (3) put the reversed halves back together in the opposite order. (Implementation left as an exercise.)
With all that said, do note that Reticality's one-liner using StringBuilder.reverse() is better on all counts if it satisfies the requirements.

My Solution-
import java.util.*;
public class MyClass {
public static void main(String args[]) {
String str = "pappap";
String sp = str.toLowerCase();
char[] ch = sp.toCharArray();
int len = ch.length;
int lastIndex = ch.length-1;
int count = 1;
int first = 0;
int last = sp.length()-1;
for(; first < last ;){
if(ch[first] == ch[last] ){
first= first+1;
last= last-1;
}
else{
count = 0;
break;
}
}
String result = (count == 1) ? "Palindrome" : "Not a palindrome " ;
System.out.println(result);
}
}

If you are checking to see if a number, given to you as a string, is a palindrome, then you might use math to do it. Use an algorithm that compares the least significant with the most significant digit, then remove those to digits and continue. If there are an odd number of digits then you don't need to compare that middle digit with anything -- you just need the number of digits / 2 steps.
This code left as an exercise because it is homework.

Related

letter change, what am I doing wrong?

So im trying the following challenge:
Using the Java language, have the function LetterChanges(str) take the str parameter being passed andmodify it using the following algorithm. Replace every letter in the string with the letter following it in thealphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
This is my code
class LetterChange {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char currentChar,letter;
int i = 0;
while (i < str.length())
{
currentChar = str.charAt(i);
for(int x = 0; x < alphabet.length(); x++)
{
letter = alphabet.charAt(x);
if (currentChar == letter){
str = str.replace(currentChar,alphabet.charAt(x+1));
i++;
}
}
}
when I run it it is returning the last char in string +1 letter in alphabet. for example if i was to run "bcd" it returns "EEE". I dont understand why its replacing all chars with the result of the loop for the last char.
When you go through the loop the first time you get
"bcd"--> "ccd"
Now, str.replace will turn this into "ddd" on next turn, then "EEE".
I.e., replace replaces every occurrence on each turn.
It is true that debugging it in the IDE will help you in the future!
Also, what if you had a lowercase vowel in your string?
public class Alphabet {
public static String LetterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
char[] string = str.toLowerCase().toCharArray();
for (int i=0; i < string.length; i++) {
char d = alphabet.charAt(((alphabet.toLowerCase().indexOf(string[i]))+1) % 26);
string[i]=d;
}
return new String(string);
}
public static void main(String[] args) {
System.out.println(Alphabet.LetterChanges("aabb"));
}
}
alphabet.charAt(
((alphabet.toLowerCase().indexOf(string[i]))
+1) % 26)
1) use toLowerCase on the input and your string map to eliminate case problems
2) find character at index+1 in string map 'alphabet', treating it as a circular buffer using a modulus that takes z to a.
index 25 (z) + 1 == 26 --> 0 (A) because 26 is 0 mod 26 while index 0(A) + 1 = 1 --> 1 mod 26. It is only necessary to wrap the z to A while not changing the other 25 indices and is more efficient than branching with an "if" statement.
Does this solution help?
public static String letterChanges(String str) {
String alphabet = "AbcdEfghIjklmnOpqrstUvwxyz";
StringBuilder stringBuilder = new StringBuilder();
for (char letter : str.toCharArray()) {
if (alphabet.contains(Character.toString(letter))) {
int index = alphabet.indexOf(letter) + 1;
if (index >= 26) {
index = 0;
}
stringBuilder.append(alphabet.charAt(index));
}
}
return stringBuilder.toString();
}
The previous solution was hard to follow, so it's difficult to explain why it wasn't working without debugging through it to see where it goes wrong. It was easier to use a for-each loop to go through the str parameter and find matches using Java's provided methods like .indexOf and .charAt.
Also, Java uses lower camel case method naming, letterChanges instead of LetterChanges :)
Let me know if you have any questions.
You are getting that result because on every replacing you are re-setting the input string. I recommend you:
Better try with two different variables: Let the input variable be unmodified, and work on the output one.
Since strings are unmodifiable -as you already know- better declare them as arrays of char.
For the shake of optimization, base your algorithm on one single loop, which will iterate over the characters of the input string. For each character, decide if it is alphabetic or not, and in case it is, what character should it be replaced with.

How to take a 1's complement of a binary String

I have a String of length >10^4 which has only binary numbers.
How can I take 1's complement of it ?
Example- Sting a = "0101"
I want String b = "1010"
Is there any better method other than replacing every character using StringBuffer/StringBuilder?
I suggest to avoid reinventing the wheel you use BigInteger. It’s not method gives you almost what you want, only it gives you a negative number when applied to a positive one. To get back into positive, add 2^n where n is the length of the original string:
String a = "0101";
BigInteger twoToLength = new BigInteger("2").pow(a.length());
String b = twoToLength.add(new BigInteger(a, 2).not()).toString(2);
System.out.println(b);
This prints:
1010
The argument 2 to the constructor and toString() is an radix indicating binary numbers.
We are not quite there yet: if the original string has leading ones, the leading zeroes in the result are not printed. You will have to prepend these manually to get the same string length as you had originally. I think the easiest way to do this is to add 2^(n+1) instead of 2^n so we are sure there is at least one 1 bit in front of the bits we really care about. So we remove this bit only after converting back to a string:
String a = "0101";
int length = a.length();
// add a couple of more bits in front to make sure we have a positive number
BigInteger twoToLengthPlus1 = BigInteger.ONE.shiftLeft(length + 1);
String b = twoToLengthPlus1.add(new BigInteger(a, 2).not()).toString(2);
// remove extra bits from the front again
b = b.substring(b.length() - length);
With this change 1010 becomes 0101.
Does it have to be a String? If a CharSequence is enough, you can do this:
public class BinaryComplementCharSequence implements CharSequence {
private final String source;
public BinaryComplementCharSequence(String source) {
this.source = source;
}
#Override
public int length() {
return source.length();
}
#Override
public char charAt(int index) {
switch (source.charAt(index)) {
case '0':
return '1';
case '1':
return '0';
default:
throw new IllegalStateException();
}
}
#Override
public CharSequence subSequence(int start, int end) {
return new BinaryComplementCharSequence(source.substring(start, end));
}
#Override
public String toString() {
return new StringBuilder(length()).append(this).toString();
}
}
If you really need a String, call toString() (but that uses a StringBuilder again).
You've already figured it out: use a StringBuilder and replace every bloody char individually.
You could also use a char array: char ca[] = str.toCharArray() to extract the characters, modify individual chars in ca, String newstr =new String(ca) to pack the array back into a String. Might be slightly faster.
Take your pick.
Every char check with '1' and invert:
char[] charsConverted = new char[a.length()];
char[] charArray = a.toCharArray();
for (int i = 0; i < charArray.length; i++) {
boolean b = charArray[i] == '1';
charsConverted[i] = !b ? '1' : '0';
}
String b= String.valueOf(charsConverted);

Longest palindrome within a word

I am trying to make a program to find the longest a palindrome within a string.
E.g., Banana -> anana
I have made a for loop to reverse the inputted string and I can make it check each time if it is a palindrome but I'm not sure it will work since the palindrome may not start at the first letter of the string.
Right now, my programs output is the following:
a
an
ana
anan
anana
ananab
In this case it would work but if the input was, say, abracadabra, the two palindromes within would be ace and ada but the program would not find it properly.
Here is my code:
public class Palindrome {
public static void main(String[] args) {
String string = "banana";
String reverse = "";
int length = string.length() - 1;
for (int i = length; i >= 0; i--) {
reverse = reverse + string.charAt(i);
System.out.println(reverse);
}
}
}
My method considers all possible substrings of the input string. For each substring it uses StringBuilder.reverse() to reverse the substring and then compare it to the original substring to determine if it was a palindrome.
private static Collection<String> longestPalindromesIn(String input) {
// longest palindromes found until now
Set<String> result = new HashSet<>();
// length of longest palindrome found until now (all strings in result have this length)
// initialize to a negative value to make sure that the first palindrome found will appear to be longer
int longest = -1;
// iterate over all possible substrings
for (int start = 0; start <= input.length(); start++) {
for (int end = start; end <= input.length(); end++) {
String currentSubstring = input.substring(start, end);
// only consider if at least as long as the longest palindrome already found
if (currentSubstring.length() >= longest) {
if (isPalindrome(currentSubstring)) {
if (currentSubstring.length() > longest) {
// discard palindromes shorter than the one we have just found
result.clear();
longest = currentSubstring.length();
}
result.add(currentSubstring);
}
}
}
}
return result;
}
private static boolean isPalindrome(String candidate) {
// the following is the easy way of reversing a string;
// you may use your own code instead if you prefer
StringBuilder reverse = new StringBuilder(candidate);
reverse.reverse();
return candidate.equals(reverse.toString());
}
For input banana the method returns a set of a single string, anana.
abracadabra gives two palindromes, aca and ada.
abca gives a, b and c. If there is no interesting palindrome (length 2 or more), the method just returns each letter. Once each, since the result is a Set and hence filters out duplicates.
If input is the empty string "", output is the empty string too. It is a palindrome after all.

Determining if two strings are a substring of a permutation of another String

So I am trying to figure out if two strings when combined together are a substring of a permutation of another string.
I have what I believe to be a working solution but it is failing some of the JUnit test cases and I dont have access to the ones that it is failing on.
here is my code with one test case
String a="tommarvoloriddle";
String b="lord";
String c="voldemort";
String b= b+c;
char[] w= a.toCharArray();
char[] k= b.toCharArray();
Arrays.sort(k);
Arrays.sort(w);
pw.println(isPermuation(w,k)?"YES":"NO");
static boolean isPermuation(char[] w, char[] k)
{
boolean found=false;
for(int i=0; i<k.length; i++)
{
for(int j=i; j<w.length; j++)
{
if(k[i]==w[j])
{
j=w.length;
found=true;
}
else
found=false;
}
}
return found;
}
any help getting this to always produce the correct answer would be awesome and help making it more efficient would be great too
What you have is not a working solution. However, you don't explain why you thought it might be, so it's hard to figure out what you intended. I will point out that your code updates found unconditionally for each inner loop, so isPermutation() will always return the result of the last comparison (which is certainly not what you want).
You did the right thing in sorting the two arrays in the first place -- this is a classic step which should allow you to efficiently evaluate them in one pass. But then, instead of a single pass, you use a nested loop -- what did you intend here?
A single pass implementation might be something like:
static boolean isPermutation(char[] w, char[] k) {
int k_idx=0;
for(w_idx=0; w_idx < w.length; ++w_idx) {
if(k_idx == k.length)
return true; // all characters in k are present in w
if( w[w_idx] > k[k_idx] )
return false; // found character in k not present in w
if( w[w_idx] == k[k_idx] )
++k_idx; // character from k corresponds to character from w
}
// any remaining characters in k are not present in w
return k_idx == k.length;
}
So we are only interested in whether the two combined strings are a subset of a permutation of another string, meaning that the lengths can in fact differ. So let's say we have:
String a = "tommarvoloriddle";
String b = "lord";
String c = "voldemort";
char[] master = a.ToCharArray();
char[] combined = (b + c).ToCharArray();
Arrays.Sort(master);
Arrays.Sort(combined);
System.out.println(IsPermutation(master, combined) ? "YES" : "NO");
Then our method is:
static boolean IsPermutation(char[] masterString, char[] combinedString)
{
int combinedStringIndex = 0;
int charsFound = 0;
int result = 0;
for (int i = 0; i < masterString.Length; ++i) {
result = combinedString[combinedStringIndex].CompareTo(masterString[i]);
if (result == 0) {
charsFound++;
combinedStringIndex++;
}
else if (result < 0) {
return false;
}
}
return (charsFound == combinedString.Length);
}
What the above method does: it starts comparing characters of the two strings. If we have a mismatch, that is, the character at the current masterString index does not match the character at the current combinedString index, then we simply look at the next character of masterString and see if that matches. At the end, we tally the total number of characters matched from our combinedString, and, if they are equal to the total number of characters in combinedString (its length), then we have established that it is indeed a permutation of masterString. If at any point, the current character in masterString is numerically greater than the current character in combinedString then it means that we will never be able to match the current character, so we give up. Hope that helps.
If two Strings are a permuation of the other you should be able to do this
public static boolean isPermuted(Strign s1, String s2) {
if (s1.length() != s2.length()) return false;
char[] chars1 = s1.toCharArray();
char[] chars2 = s2.toCharArray();
Arrays.sort(chars1);
Arrays.sort(chars2);
return Arrays.equals(chars1, chars2);
}
This means that when sorted the characters are the same, in the same number.

Efficient way to find Frequency of a character in a String in java : O(n)

In a recent interview I was asked to write the below program.
Find out the character whose frequency is minimum in the given String ?
So I tried by iterating through the string by using charAt and storing the character as key in a HashMap and the number of occurences as its value.
Now Again I have to iterate on the Map to find the lowest element.
Is there a more efficient way to do it as obviously the above one is too intensive i guess.
Update and Another Solution
After some thought process and answers I think the best time that this can be is O(n).
In the first iteration we will have to iterate through the String character by character and then store their frequency in an Array at the specific position(character is an int) and same time have two temporary variables which maintain the least count and the corresponding character.So when I go to the next character and store its frequency in arr[char] = arr[char]+1;At the same time I will check if the temp varible has a value greater than this value,if yes then the temp varible will be this value and also the char will be this one.In this way i suppose we dont need a second iteration to find the smallest and also no sorting is required I guess
.... Wat say ? Or any more solutions
I'd use an array rather than a hash map. If we're limited to ascii, that's just 256 entries; if we're using Unicode, 64k. Either way not an impossible size. Besides that, I don't see how you could improve on your approach. I'm trying to think of some clever trick to make it more efficient but I can't come up with any.
Seems to me the answer is almost always going to be a whole list of characters: all of those that are used zero times.
Update
This is probably clost to the most efficient it could be in Java. For convenience, I'm assuming we're using plain Ascii.
public List<Character> rarest(String s)
{
int[] freq=new int[256];
for (int p=s.length()-1;p>=0;--p)
{
char c=s.charAt(p);
if (c>255)
throw new UnexpectedDataException("Wasn't expecting that");
++freq[c];
}
int min=Integer.MAX_VALUE;
for (int x=freq.length-1;x>=0;--x)
{
// I'm assuming we don't want chars with frequency of zero
if (freq[x]>0 && min>freq[x])
min=freq[x];
}
List<Character> rares=new ArrayList<Character>();
for (int x=freq.length-1;x>=0;--x)
{
if (freq[x]==min)
rares.add((char)x);
}
return rares;
}
Any effort to keep the list sorted by frequency as you go is going to be way more inefficient, because it will have to re-sort every time you examine one character.
Any attempt to sort the list of frequencies at all is going to be more inefficient, as sorting the whole list is clearly going to be slower than just picking the smallest value.
Sorting the string and then counting is going to be slower because the sort will be more expensive than the count.
Technically, it would be faster to create a simple array at the end rather than an ArrayList, but the ArrayList makes slightly more readable code.
There may be a way to do it faster, but I suspect this is close to the optimum solution. I'd certainly be interested to see if someone has a better idea.
I think your approach is in theory the most efficient (O(n)). However in practice it needs quite a lot of memory, and is probably very slow.
It is possibly more efficient (at least it uses less memory) to convert the string to a char array, sort the array, and then calculate the frequencies using a simple loop. However, in theory it is less efficient (O(n log n)) because of sorting (unless you use a more efficient sort algorithm).
Test case:
import java.util.Arrays;
public class Test {
public static void main(String... args) throws Exception {
// System.out.println(getLowFrequencyChar("x"));
// System.out.println(getLowFrequencyChar("bab"));
// System.out.println(getLowFrequencyChar("babaa"));
for (int i = 0; i < 5; i++) {
long start = System.currentTimeMillis();
for (int j = 0; j < 1000000; j++) {
getLowFrequencyChar("long start = System.currentTimeMillis();");
}
System.out.println(System.currentTimeMillis() - start);
}
}
private static char getLowFrequencyChar(String string) {
int len = string.length();
if (len == 0) {
return 0;
} else if (len == 1) {
return string.charAt(0);
}
char[] chars = string.toCharArray();
Arrays.sort(chars);
int low = Integer.MAX_VALUE, f = 1;
char last = chars[0], x = 0;
for (int i = 1; i < len; i++) {
char c = chars[i];
if (c != last) {
if (f < low) {
if (f == 1) {
return last;
}
low = f;
x = last;
}
last = c;
f = 1;
} else {
f++;
}
}
if (f < low) {
x = last;
}
return (char) x;
}
}
The process of finding frequency of characters in a String is very easy.
For answer see my code.
import java.io.*;
public class frequency_of_char
{
public static void main(String args[])throws IOException
{
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
int ci,i,j,k,l;l=0;
String str,str1;
char c,ch;
System.out.println("Enter your String");
str=in.readLine();
i=str.length();
for(c='A';c<='z';c++)
{
k=0;
for(j=0;j<i;j++)
{
ch=str.charAt(j);
if(ch==c)
k++;
}
if(k>0)
System.out.println("The character "+c+" has occured for "+k+" times");
}
}
}
I'd do it the following way as it involves the fewest lines of code:
character you wish to want to know frequency of: "_"
String "this_is_a_test"
String testStr = "this_is_a_test";
String[] parts = testStr.split("_"); //note you need to use regular expressions here
int freq = parts.length -1;
You may find weird things happen if the string starts or ends with the character in question, but I'll leave it to you to test for that.
Having to iterate through the HashMap is not necessarily bad. That will only be O(h) where h is the HashMap's length--the number of unique characters--which in this case will always be less than or equal to n. For the example "aaabbc", h = 3 for the three unique characters. But, since h is strictly less than the number of possible characters: 255, it is constant. So, your big-oh will be O(n+h) which is actually O(n) since h is constant. I don't know of any algorithm that could get a better big-oh, you could try to have a bunch of java specific optimizations, but that said here is a simple algorithm I wrote that finds the char with the lowest frequency. It returns "c" from the input "aaabbc".
import java.util.HashMap;
import java.util.Map;
public class StackOverflowQuestion {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("" + findLowestFrequency("aaabbc"));
}
public static char findLowestFrequency(String input) {
Map<Character, Integer> map = new HashMap<Character, Integer>();
for (char c : input.toCharArray())
if (map.containsKey(c))
map.put(c, map.get(c) + 1);
else
map.put(c, 0);
char rarest = map.keySet().iterator().next();
for (char c : map.keySet())
if (map.get(c) < map.get(rarest))
rarest = c;
return rarest;
}
}

Categories