substring() method in a Palindrome - java

In a well know recursion isPalindrome method
public static boolean isPalindrome(String s){
if(s.length() == 0 || s.length() == 1)
return true;
if(s.charAt(0) == s.charAt(s.length()-1))
return isPalindrome(s.substring(1, s.length()-1));
return false;
}
}
there is one line that I dont quite understand. If, for example we pass the string anna to the isPalindrome method, what does this line of code
return isPalindrome(s.substring(1, s.length()-1));
do to the string when s has a value of nn ?
In my understanding number 1 (index 1) is for second letter n, and s.length()-1 is equal 2-1 = 1, but not including that index position, so that must be index 0 ??
Does it return an empty string or something else ?

When the value of s is nn, as we step through the statements, this will happen:
s.length() is 2, so the first if condition doesn't match
s.charAt(0) is n, and s.charAt(1) is n, so the second if matches
Return the result of isPalindrome with parameter s.substring(1, 1), which is the text range from position 1 until before the position 1, in other words, an empty string
In the recursive call with empty string as input, isPalindrome will match the first condition on length, and return true
For the record, this is a very inefficient way to check a palindrome in Java,
because substring creates new strings, which is slow.
A more efficient recursive solution is possible by adding start and end index parameters, and moving them inward, until their difference becomes 0 or 1.

The return isPalindrome(s.substring(1, s.length() - 1)); will "loop" by sending the string value that you have without the first and last characters — or from the second till the second-last (a.k.a. penultimate). Then it will compare again that string; then it will "loop" again by using the same routine.
I think your "confusion" may lie in the fact that s.length() will return how many characters s have (counting naturally from 1..N); but s.substring(...) works with indexes, and they start with 0 (not at 1). In that "fashion", the last character will be the length minus one.
Example:
String example = "Five"; // ["F", "i", "v", "e"]
// 0 1 2 3 <--- indexes
// Length is four (it has 4 characters)

Related

What happens when if statement goes true (in this code)?

There is a problem in codingbat.com which you're supposed to remove "yak" substring from the original string. and they provided a solution for that which I can't understand what happens when the if statement goes true!
public String stringYak(String str) {
String result = "";
for (int i=0; i<str.length(); i++) {
// Look for i starting a "yak" -- advance i in that case
if (i+2<str.length() && str.charAt(i)=='y' && str.charAt(i+2)=='k') {
i = i + 2;
} else { // Otherwise do the normal append
result = result + str.charAt(i);
}
}
return result;
}
It just adds up i by 2 and what? When it appends to the result string?
Link of the problem:
https://codingbat.com/prob/p126212
The provided solution checks for all single characters in the input string. For this i is the current index of the checked character. When the current char is not a y and also the (i+2) character is not a k the current char index is advanced by 1 position.
Example:
yakpak
012345
i
So here in the first iteration the char at i is y and i+2 is a k, so we have to skip 3 chars. Keep in mind i is advanced by 1 everytime. So i has to be increased by 2 more. After this iteration i is here
yakpak
012345
i
So now the current char is no y and this char will get added to the result string.
But it's even simpler in Java as this functionality is build in with regex:
public String stringYak(String str) {
return str.replaceAll("y.k","");
}
The . means every char.
If i is pointing at a y and there is as k two positions down, then it wants to skip the full y*k substring, so it add 2 to i so i now refers to the k. WHen then loop continues, i++ will skip past the k, so in effect, the entire 3-letter y*k substring has been skipped.

String index out of range - java

What does that mean? The length of the string is too long or there is error in my code?
public class Program {
public static String flipEndChars(String s) {
if(s.charAt(0) == s.charAt(s.length())){
return "Two's a pair.";
}
else if(s.length()<3){
return "incompatible";
}
else
return s.charAt(s.length()) + s.substring(1,s.length()) + s.charAt(0);
}
}
the issue is with this part :
s.charAt(s.length())
It's trying to access a character beyond the length of your string. The indexation is zero based, so the last character of a string is always at index s.length() - 1
String.charAt(int) returns the char at the specified index, where 0 is the first character, 1 is the second character, 2 is the third, and so on.
"hello".charAt(0) returns the character h.
String.length() returns the length of the string.
"hello".length() returns 5. So if you call "hello.charAt(5)", this will get the 6th character in the String "hello", which does not exist. This will throw an IndexOutOfBoundsException.
I hope this helps.

A java string exercise i came across

Look for patterns like "zip" and "zap" in the string -- length-3, starting with 'z' and ending with 'p'. Return a string where for all such words, the middle letter is gone, so "zipXzap" yields "zpXzp"
Here is a solution i got from someone:
public class Rough {
public static void main(String [] args){
StringBuffer mat = new StringBuffer("matziplzdpaztp");
for(int i = 0; i < mat.length() - 2; ++i){
if (mat.charAt(i) == 'z' & mat.charAt(i + 2) == 'p'){
mat.deleteCharAt(i + 1);
}
}
System.out.println(mat);
}
}
But why is it that the for loop condition (i < mat.length() -2) is not (i < mat.length())????
Because in the loop:
if (mat.charAt(i) == 'z' & mat.charAt(i + 2) == 'p'){
// -----------------------------------^^^^^
If i were bound by i < mat.length(), then i + 2 would be out of bounds.
Because you don't have to reach the end of your sentence since your words are at least three letters long.
"2" stands for "the length except the first word",you just need to check all the positions in the string variable , and treat the positions as the first word of the substring , so just ignore the "length of the substring without the first word".
in your case , the length of "z*p" is 3, you just check all the position in the string , and treat the position as z to check something ,so just ignore "*p" ,which has length 2.
mat.length() will give length 14 and if you check for mat.charAt(i + 2) at the end it will give java.lang.StringIndexOutOfBoundsException because the string counts from index 0 not from 1. If you still want to use mat.length() you have to replace the AND '&' operator with short circuit AND '&&' operator in if condition.

Cannot invoke equals(boolean) on the primitive type boolean

I want to check equality of first and last two characters of a string so i have written condition like
if (str.length() >= 4
&& ((str.startsWith(str.substring(0, 2))).equals(str.endsWith(str
.substring(str.length() - 3, str.length() - 1)))))
but I am getting error as
Cannot invoke equals(boolean) on the primitive type boolean
so what is the root cause?
Error is coming because : str.startsWith() returns boolean value and we are calling equals() with Boolean
Use this expression to compare :
str.substring(0, 2).equals(str.substring(str.length() - 3, str.length() - 1))
I want to check equality of first and last two characters of a string
That's not what you're doing though. You're using startsWith and endsWith - you're asking whether a string starts with its own first two characters, and whether it ends with some portion of the string near the end, and then trying to compare the results of those comparisons... except that you're trying to compare two boolean values with equals instead of ==, which isn't going to work either.
You just want substring and equals here - but your substring is incorrect too, in that you have an off-by-one error for finding the last two characters. I would personally split this up for simplicity:
if (str.length() > 4) {
String start = str.substring(0, 2);
// If you don't specify an end point, it'll be "the rest of the string"
// which is what you want.
String end = str.substring(str.length() - 2);
if (start.equals(end)) {
...
}
}
endsWith api will return you a boolean value and hence compiler is compiling that you are trying to compare String with boolean. Instead you could do something like:
if (str.endsWith(str.substring(0, 2))) {
//ye it does ends with same string as it starts with
}
The method startsWith(String) returns a boolean indicating if the string it is being applied on effectively starts with the string argument. For comparing the first two characters with the last two ones, your boolean condition can be:
if(str.length() >= 4 && str.startsWith(str.substring(str.length - 3, str.length()))
Be careful with the indices in the substring method since the last parameter indicates the place of the first character not to be included in the substring.
Same result but with the endsWith(String) method:
if(str.length() >= 4 && str.endsWith(str.substring(0, 3)))
Or with only sunbstring(int, int) method:
if(str.length() >= 4
&& str.substring(0, 3).equals(str.substring(str.length() - 3, str.length())))
Your problem stems from
((str.startsWith(str.substring(0, 2))).equals(str.endsWith(str
.substring(str.length() - 3, str.length() - 1))))
Which is basically coming down to boolean.equals(...), which can't be done, as boolean is not an Object
You could, instead, make use of String#startsWith and String#endsWith, for example...
if (str.length() >= 4 &&
str.endsWith(str.substring(0, 2)) &&
str.startsWith(str.substring(str.length() - 2))) {
Or maybe even
if (str.length() >= 4 &&
str.substring(0, 2).equals(str.substring(str.length() - 2))) {

get wrong output of a recursive method

public static int getIndexOf(char ch, String str) {
if (str == null || str.equals("")) {
return 0;
//base case
}else{
char first = str.charAt(0);
if (ch != first) {
return -1;
//returns -1 when the character cannot be found within the string
}else{
int rest = str.length() - 1;
if (str.charAt(rest) == ch) {
return rest;
}
return lastIndexOf(ch, str.substring(0, rest));
//recursive case
}
}
}
This my method which returns the index of the input character of the input string. However, when I run it in the interaction plane, it returns wrong number. For example, when I enter 'a' and "peach", it is supposed to return 2, but it returns -1. This method should return -1 only when the character cannot be found in the string. Can anyone tell me how to deal with it?
Thank you!
Well why don't you step through the logic and see what happens.
getIndexOf('a', "peach")
Method goes in, string isn't null or empty so it falls through to the next line of code.
char first = str.charAt(0); // this is 'p'
if (ch != first) { // is 'p' equal to 'a'? no. so return -1
return -1;
And then the rest of your logic will never execute. Can you see how to fix this problem?
your following portion of code means that it will check for the first character of the string if it is matching otherwise it will return -1.
char first = str.charAt(0);
if (ch != first) {
return -1;
this says that if character at 0th index doesn't match then send -1 so as 'p' in "peach" isn't matching with 'a' so it is return -1.
did you get it?
The output's not wrong, the implementation is!
Think in words first. If the desired character is the first character in the string, then the result is zero. Otherwise it's (1 + the index in the string that remains after cutting off the first character). Now code the words:
return (str.charAt(0) == ch) ? 0 : 1 + getIndexOf(ch, str.substring(1));
This doesn't yet handle the case where the character is not in the string at all. Here the charAt(0) call will eventually throw IndexOutOfBoundsException because str doesn't have one!
The cleanest way to handle this case is to catch the exception. So you's have two functions: mustGetIndexOf, which is the recursive relation above, and getIndexOf, which calls the one above inside a try {} catch() {}, returning -1 in that case.
Of course if you don't want to allow the exception, you can test the recursive call's result with if for the special case of -1. The code is uglier, but it will work. Whenever a -1 is seen, return -1 again. This propagates the -1 all the way back to the caller. The exception "unwinds" the recursive calls on the stack in a similar manner, just with one chop instead of the gradual call-by-call way your if statements will do it.
I won't give you full code so you can continue to learn.

Categories