I am attempting to write a method that tests to see if a string is a palindrome. This is what I have so far:
public static boolean isPalindrome(String word) {
boolean flag = false;
if (word.length() < 2) {
flag = true;
} else if (word.charAt(0) == word.charAt(word.length() - 1)) {
flag = isPalindrome(word.substring(1, word.length() - 2));
}
return flag;
}
The problem I'm running into is, this method consistently returns true for strings of the form "aaaba", where the pair that should cause false to be propagated back through the stack is in the middle of the string. I'm banging my head against the wall trying to see where my error is, but to no avail. Perhaps a fresh set of eyes will see something I'm missing?
In your recursive call, you should subtract 1 from the length of the string, not 2:
// start index inclusive, end index exclusive
flag = isPalindrome(word.substring(1, word.length() - 1));
Change the endIndex in the substring(startIndex, endIndex) method. Note that according to Java Docs:
public String substring(int beginIndex, int endIndex)
Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1.
Change it to:
word.substring(1, word.length() - 1)
so, let's say word = "aaba", this method will return "ab".
Also, you can simplify your code by getting rid of flag and returning the result directly:
public static boolean isPalindrome(String word)
{
if (word.length() < 2) {
return true;
} else if (word.charAt(0) == word.charAt(word.length() - 1)) {
return isPalindrome(word.substring(1, word.length() - 1));
} else {
return false;
}
}
Try this....
public static boolean isPalindrome(String word) {
if(word.length() == 0 || word.length() == 1)
return true; // If length is 0 or 1 then it is palindrome
if(word.charAt(0) == word.charAt(word.length()-1))
return isPalindrome(word.substring(1, word.length()-1));
//Check the first and last char of the string if they are same
//then continue the same for a substring by removing the first
//and last character. And continue this until the string completes
return false; //I fthe case doesn't match
}
Related
This question already has answers here:
Check string for palindrome
(42 answers)
Closed 2 years ago.
Problem is to check if the string is valid palindrome or not. Return true for empty strings.
What's the problem with my code? It is failing for the input "ab"
public class Solution {
Boolean b;
public Boolean isPalindrome(String s) {
s = s.toLowerCase();
s = s.replaceAll("[^a-zA-Z0-9]","");
if(s.length()==1 || s.isEmpty())
{
return true;
}
for (int i=0;i<s.length()-1;i++)
{
b = expandAroundCenter(s,i,i+1);
b = expandAroundCenter(s,i,i);
}
return b;
}
public Boolean expandAroundCenter(String s,int start,int end)
{
while(start>=0 && end<s.length() )
{
if ((s.charAt(start))!=(s.charAt(end)))
{
return false;
}
start--;
end++;
}
return true;
}
}
You've got big logic flaws here.
Firstly, in your for loop you call expandAroundCenter twice, and overwrite the first results.
Secondly, you're doing this in a for loop, and overwriting all previous results.
Also I think you're making things harder than they need to be by starting in the middle. Start on the edges, and work inward!
Calculating a palindrome is a great opportunity for a recursive function (one that calls itself). I'll give you the pseudo-code, it's up to you to implement:
public Boolean IsPalindrome(string s)
// If we are down to 1 or zero characters, success!
// This deals nicely with odd numbered length strings
if(length <= 1)
return true;
// If the first and last don't match, it's not a palindrome
if(first letter != last letter)
return false;
// Since we know the first and last match, strip them off, then repeat
return IsPalindrome(strip first and last letter from string)
}
If there are no constraints, the best way to solve this problem is to use recursive.
class palindrome
{
static boolean isPalRec(String str,
int s, int e)
{
if(s == "")
return true;
if (s == e)
return true;
if ((str.charAt(s)) != (str.charAt(e)))
return false;
if (s < e + 1)
return isPalRec(str, s + 1, e - 1);
return true;
}
static boolean isPalindrome(String str)
{
int n = str.length();
if (n == 0)
return true;
return isPalRec(str, 0, n - 1);
}
}
I am having trouble rewriting the following code as a recursive method rather than using the for loop. The for loop tests to see if the String 'noSpaces' is a palindrome (the same forwards as it is backwards). The noSpaces String has no punctuation, spaces, or differences in capitalization.
Thanks for the help
public boolean isRegularPalindrome(String noSpaces) {
noSpaces = noSpaces.toUpperCase();
String[] letters = new String[noSpaces.length()];
for (int i = 0; i < letters.length; i++) {
letters[i] = Character.toString(noSpaces.charAt(i));
}
for (int i = 0; i < letters.length / 2; i++) {
if (!letters[i].equals(letters[letters.length - i - 1])) {
return false;
}
}
return true;
}
There you go:
public static boolean isPalindrome(String input) {
if (input.charAt(0) != input.charAt(input.length() - 1)) {
// Missmatch. Not a palindrome!
return false;
} else if (input.length() > 1){
// If there is more to test, continue.
return isPalindrome(input.substring(1, input.length() - 1));
} else {
// All chars were tested, or 1 char input. Palindrome!
return true;
}
}
Writing a recursive algorithm for anything requires base cases. For a palindrome, this would be a string of length 0 or length 1 -- if the string is length 0 or 1, it is a palindrome.
If the base cases aren't met, you check the first character against the last character.
If the characters aren't the same, return false.
If the characters are the same, return the recursive call to the string except for the first and last characters.
The code should look something like this.
public boolean isPalindrome(string str){
if (str.length == 0)
return true;
else if (str.length == 1)
return true;
else if(str.charAt(0) != str.charAt(str.length - 1)
return false;
else
return isPalindrome(str.substring(1, length - 1));
}
The method below takes in a string and a pattern and returns true if they match each other. A '.' matches 1 char and a '*' matches 0 or more (e.g. expMatch("abc", "a.c") should return true). I added a bunch of print statements to see where I went wrong and it seems like the if statement is being skipped even if the str.length() == 1.
I call it with System.out.println(expMatch("abc", "a*c"));
Here is the code:
public static boolean expMatch(String str, String pat)
{
if (str.charAt(0) == pat.charAt(0) || pat.charAt(0) == '.')
{
System.out.println("in if");
System.out.println(str.charAt(0));
System.out.println(pat.charAt(0));
System.out.println(str.length());
if (str.length() == 1)
return true;
expMatch(str.substring(1), pat.substring(1));
}
else if (pat.charAt(0) == '*')
{
System.out.println("in else");
System.out.println(str.charAt(0));
System.out.println(pat.charAt(0));
if (str.length() == 1)
return true;
if (str.charAt(0) == pat.charAt(1)) //val of * = 0
expMatch(str, pat.substring(1));
else if (str.charAt(1) ==pat.charAt(1))
expMatch(str.substring(1), pat.substring(1));
}
return false;
}
and the output is:
in if
a
a
3
in else
b
*
in if
c
c
1
false
Even if the length is 1 it skips the if? Any idea why?
P.S. I'm not looking for the solution, just why the if statement is being skipped.
You always return false from the method at the very end. You are calling expmatch recursively but never using the return value. The code comes in to the first if, recurses (because length is not 1) and upon returning will go to the final return statement which returns false.
You need to add a return before your expMatch() calls - because the false comes from your last line return false;
What happens is this:
you call expMatch() with the two Strings.
you enter the if clause
the if clause enters expMatch() recursively
you enter the else clause
the else clause enters expMatch() recursively
you enter the if clause again
you leave the expMatch() method
you leave the other expMatch method
false is returned
Your approach is logically incorrect even if you apply the fixes the others suggested. Try this test case:
System.out.println(expMatch("abddddc", "a*c"));
This is because when you encounter a * in the pattern, you have no way to know how many characters "to eat" from the search string.
To say the least, you need a loop somewhere, not just an if. Let me try to fix it for you (not sure if it's possible though, not sure if you always know which path to take, I mean in your recursion). Think some more about it. Here is another unpleasant test case:
System.out.println(expMatch("adddcac", "a*c"));
// the * needs to eat dddca (despite the c present in dddca),
// it should not stop recursing there at that c
I think you need some sort of full search here.
Just an if or a while loop is not good enough.
EDIT: Here is a fixed version with a bunch of nasty tests. I think this is called non-linear recursion (as it's not a single path you try). Not 100% sure though about that term.
public class Test055 {
public static void main(String[] args) {
// System.out.println(expMatch("abddddc", "a*c"));
System.out.println(expMatch("adcax", "a*c"));
System.out.println(expMatch("adcax", "a*c*"));
System.out.println(expMatch("adcacm", "*"));
System.out.println(expMatch("adcacmmm", "a*c"));
System.out.println(expMatch("adcacmmmc", "a*c"));
System.out.println(expMatch("adcac", "a*c"));
System.out.println(expMatch("adcacxb", "a*c.b"));
System.out.println(expMatch("adcacyyb", "a*c.b"));
System.out.println(expMatch("adcacyyb", "a*c*b"));
}
public static boolean expMatch(String str, String pat)
{
// System.out.println("=====================");
// System.out.println("str=" + str);
// System.out.println("pat=" + pat);
if (pat.length() == 0 && str.length() > 0) {
return false;
} else if (pat.length() == 0 && str.length() == 0) {
return true;
} else if (pat.charAt(0) == '.'){
return str.length() >= 1 && expMatch(str.substring(1), pat.substring(1));
}else if (pat.charAt(0) != '*'){
return str.length() >= 1 && pat.charAt(0) == str.charAt(0) && expMatch(str.substring(1), pat.substring(1));
}else{
// Now let's handle the tricky part
// (1) Look for the 1st non-star in pattern
int k=-1;
char ch = ' ';
for (int i=0; i<pat.length(); i++){
if (pat.charAt(i) != '*'){
k = i;
ch = pat.charAt(k);
break;
}
}
if (k==-1){
// (2A) only stars found in pattern, OK, any str matches that
return true;
}else{
// (2B) do full search now checking all
// possible candidate chars in str that
// match the char ch from pattern
for (int i=0; i<str.length(); i++){
if (str.charAt(i)==ch){
boolean b = expMatch(str.substring(i+1), pat.substring(k+1));
if (b) return true;
}
}
return false;
}
}
}
}
I'm working on a recursion problem from codingbat.com which states
Given a string, compute recursively a new string where all the lowercase 'x' chars have been moved to the end of the string.
It passes all of the examples except for the example that says "other tests." Since i can't see what "other tests" are referring to, I'm stuck. Any help would be appreciated. Here's my code
public String endX(String str) {
return endX2(str, 0, str.length());
}
public String endX2(String str, int n, int len){
if(len == 0) return str;
if(n == len-1) return str;
if(str.substring(n,n+1).equals("x")){
return str.substring(0,n) + (endX2(str.substring(n+1) + "x", n, len-1));
}
else return endX2(str, n+1, len);
}
I'm not sure why you have an additional method as it's unnecessary. You also have an additional check - if(n == len-1) return str; - that isn't needed.
The problem you're facing is the fact you're using unchecked indices and are getting lucky when the strings used do not end with an 'x' or a number of 'x's. If I use your code against String xs = "xfooxbarxx"; gets me a java.lang.StringIndexOutOfBoundsException. I haven't debugged the code extensively, but that should bring some understanding to the reason why it fails on the "other" tests. Take a look at my version and investigate for yourself where the issue may lie and how to perhaps make your code a bit more concise.
public String endX(String str) {
if(str.length() == 0)
return "";
return str.startsWith("x") ?
endX(str.substring(1)) + "x" :
String.valueOf(str.charAt(0)) + endX(str.substring(1));
}
PS: This is WAY WAY longer than it needs to be.
/*
Alright here is what we need to do...
Step 1: Get all the 'x' chars into a String.
Step 2: Get all NON 'x' chars into a String.
Step 3 (goal): Concencate (combine) the NON 'x' String first then the 'x' String in that order.
Solution Notes: Instead of using an index variable to go through a String, we could 'substring' off the first char in the String each time, cutting until we are down to the base case, for the sake of showing recursive logic I used an index varible. However on Arrays or any other collection, you need an index varible to access that element ant that spot or (index).
*/
public String endX(String str) {
//Ternary operator used here...could be written as a full if then else statement.
//Ternary operator logic: if the length is 0 return "", else return getNonX(str, "", 0) + getX(str, "", 0);
return (str.length() == 0) ? "" : getNonX(str, "", 0) + getX(str, "", 0);
//NOTICE in the parts [getNonX(str, "", 0)] and [getX(str, "", 0)]
//there is an empty String in the middle, that is there to hold or gather the
//chars, 'x' or not. We fill those empty Strings up in each recursive helper
}
public String getX(String str, String x, int index) {
//We are at the end, and if the last char IS an 'x'...
if(index == str.length() - 1 && str.charAt(index) == 'x'){
return x + 'x'; //...put that last 'x' on the 'x' String.
}
//We are at the end and if the last char IS NOT an 'x'...
else if(index == str.length() - 1 && str.charAt(index) != 'x'){
return x; //...just return what we got.
}
//When we see an 'x' but we aren't at the end...
if(index < str.length() - 1 && str.charAt(index) == 'x'){
x += 'x'; //...append 'x' to the 'x' String.
}
return getX(str, x, index + 1); //recur, moving the index up
}
public String getNonX(String str, String nonX, int index) {
//We are at the end, and if the last char IS NOT an 'x'...
if(index == str.length() - 1 && str.charAt(index) != 'x'){
return (nonX + str.charAt(index)); //...append that char to the 'nonX' String
}
//We are at the end and if the last char IS an 'x'...
else if(index == str.length() - 1 && str.charAt(index) == 'x'){
return nonX; //...just return what we got.
}
//When we see a non 'x' char and we aren't at the end...
if(index < str.length() - 1 && str.charAt(index) != 'x'){
nonX += str.charAt(index); //...append that char to the 'nonX' String
}
return getNonX(str, nonX, index + 1); //recur, move the index up
}
You can try this code...
public String endX(String str) {
if(str.length() <=1) return str;
if(str.charAt(0) == 'x') return endX(str.substring(1)) + 'x';
return str.charAt(0) + endX(str.substring(1));
}
Here is what I have for method lastIndexOf , ch is the character to match, and str is the source string.
public static int lastIndexOf(char ch, String str) {
// check for null string or empty string
if (str.length() == 0 || str == null) {
return -1;
}
int indexInRest = lastIndexOf(ch, str.substring(1));
char first = str.charAt(0);
// recursive call to find the last matching character
if (first == ch) {
return 1 + indexInRest; // this might not work properly
} else
return indexInRest;
}
If in my class' main method I call:
System.out.println(lastIndexOf('r', "recurse"));
System.out.println(lastIndexOf('p', "recurse"));
I got:
1
-1
The desired result is:
4
-1
Suggestion, please.
How about taking the functional approach..
public static int lastIndexOf(char ch, String str) {
if (str.charAt(str.length() - 1) == ch) { return str.length() -1; }
if (str.length() <= 1) { return -1; }
return lastIndexOf(ch, str.substring(0, str.length() - 1));
}
This must be homework because there would be no point to writing this method since String.lastIndexOf() exists in the API, and using recursion to do this going to be slow and use a lot of memory.
Here a hint. Right now your algorithm is chopping characters off the front ( substring(1) ) and comparing them. lastIndexOf() should start by removing characters at the back of the String looking for a match then quit when it finds one.
why not use String.lastIndexOf like this:
str.lastIndexOf(ch)
Use the String#lastIndexOf(int ch) implementation as a general guideline,
public int lastIndexOf(int ch) {
return lastIndexOf(ch, value.length - 1);
}
public int lastIndexOf(int ch, int fromIndex) {
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
final char[] value = this.value;
int i = Math.min(fromIndex, value.length - 1);
for (; i >= 0; i--) {
if (value[i] == ch) {
return i;
}
}
return -1;
} else {
return lastIndexOfSupplementary(ch, fromIndex);
}
}
private int lastIndexOfSupplementary(int ch, int fromIndex) {
if (Character.isValidCodePoint(ch)) {
final char[] value = this.value;
char hi = Character.highSurrogate(ch);
char lo = Character.lowSurrogate(ch);
int i = Math.min(fromIndex, value.length - 2);
for (; i >= 0; i--) {
if (value[i] == hi && value[i + 1] == lo) {
return i;
}
}
}
return -1;
}
And this,
lastIndexOf(ch, value.length - 1);
value is the target String as a character array.
First, you should change to:
if (str == null || str.length() == 0) {
Because a NPE could raise if str is null
Add a deep paramater to your code like this:
public static int lastIndexOf(char ch, String str, int deep) {
And increment its value every recursive call
int indexInRest = lastIndexOf(ch, str.substring(1), deep++);
then, in the return sentence, add deep to your returned value:
return 1 + indexInRest + deep; // this might not work properly
Call the function the first time with deep = 0, or better yet, make the two parameter method lastIndexOf call the 3 parameters version of lastIndexOf with the deep parameter set to 0
You can also use Matcher in order to anticipate evolution of string analysis asked by your homework:
public int getlastMatch(String searchPattern,String textString) {
int index = -1;
Pattern pattern = Pattern.compile(searchPattern);
Matcher matcher = pattern.matcher(textString);
while(matcher.find()) {
index = matcher.start();
}
return index;
}
where textString may be your concerned character.
Thus returning the last occurence of a part of string within a string.