首先,我并不是要求人们“做我的功课”,就像我在这里看到别人要求的那样。我已设法编写一个程序的工作迭代版本,以确定字符串是否是回文。在确定字符串是否为回文时,将忽略空格,标点符号和特殊字符。这个版本确实有效但是当我尝试在“isPalindrome()”方法中应用递归语句时,我得到Stack Overflow错误。我知道这些错误是什么,只是在这样的程序中应用递归方法对我来说很难解决(我2周前才得到它们的教导)。无论如何这里是我到目前为止编译(和运行)的代码:
/** Palindrome.java: A sigle application class that determines if a word or a string
* is a palindrome or not. This application is designed to ignore spaces between
* chars, punctuation marks and special characters while determining if the word or
* string is a palindrome or not.
*
**/
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.*;
public class Palindrome{
static String palindrome, str, str2, str3;
/** The main method of the Palindrome application. Takes input from the
* user, removes spaces from their input, turns their string input into
* lowercase and then all non letter characters are taken out of the user's
* input. Finally the recursive method determines if the string entered in
* by the user is a palindrome.
*
* @param args Takes in a string array of arguements
**/
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while(input.hasNext()){
str = removeSpaces(input.nextLine());
str2 = str.toLowerCase();
str3 = normalise(str2);
}
System.out.println(isPalindrome(str3));
}
/** The default constructor
**/
public Palindrome(){
}
/** isPalindrome(): A boolean method that is passed through a String input
* and uses a for loop, two inner while loops and an if-else to determine
* whether the users input is a palindrome.
*
* @param s The string input to be tested
* @return true The users input is a palindrome
* @return false The users input isn't a palindrome
**/
public static boolean isPalindrome(String s){
int first, last;
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
first++;
}
while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
last--;
}
}
if( first > last || s.charAt(first) != s.charAt(last) ){
//return isPalindrome(s.substring(0, s.length()-1)) == false;
return false;
}
else{
//return isPalindrome(s.substring(0, s.length()-1)) == true;
return true;
}
}
/**
* This method takes out punctuation marks in the string parsed
* through, using Java's regular expressions (regex) and Java's
* inbuilt method replaceAll(). The regex expression is passed
* through the replaceAll() method to remove all non alpha-numeric
* characters from the string passed through the method's parameter.
*
* @param t The string that will have punctuation stripped from it.
*
* @return t The string has had all non alpha-numeric characters
* removed and the new string is then returned.
*/
public static String normalise(String t){
t = t.replaceAll("[^a-zA-Z0-9]", "");
return t;
}
/** removeSpaces(): A method that deletes spaces from the users input
* and then decrements the string length count so any indexes aren't missed
* when it is incremented.
*
* @param s The string which is going to have it's spaces removed.
* @return temp The new string is then returned after the spaces have been taken out.
**/
public static String removeSpaces(String s){
StringBuilder temp = new StringBuilder(s); //creates a new StringBuilder with the inputted String
for(int i = 0; i < temp.length(); i++){ //do this for the entire length of the StringBuilder
if(temp.charAt(i) == ' '){ //if the char at i is a space
temp.deleteCharAt(i); //remove the char
i--; //subtract 1 from the counter so we don't miss an index when we increment it
}
}
return temp.toString(); //return the new String
}
}
我现在已经在递归方法中消除了递归语句。如果有人可以告诉我我做错了什么,并帮助我实施一个非常好的解决方案。我宁愿坚持使用迭代版本,因为我理解它的机制,但是已经被要求做一个递归版本(我从去年年中休息以来一直是Java编码但是在递归时相对新手)这证明了是一个很大的挑战。如果您更改代码并最终使用递归版本,请解释您的更改的方式,时间,原因等。我不是在寻找有人为我做这件事,我想要学习,似乎我已经通过实例学到了最好的东西(去年我通过分析实例并阅读实施说明获得了B通过)。非常感谢:)。
编辑:我想我现在已经让递归正常,只是逻辑是令我困惑的事情。以下是isPalindrome()方法的重新编码版本: public static boolean isPalindrome(String s){
int first, last;
boolean isPalindr = true;
if (s.length() <= 1){
return true; // Base case
}
for(first = 0, last = s.length()-1 ; first < last ; first++ , last-- ){
// while( (int)s.charAt(first) < 'a' || (int)s.charAt(first) > 'z' ){
// first++;
// }
// while( (int)s.charAt(last ) < 'a' || (int)s.charAt(last ) > 'z' ){
// last--;
// }
// }
if( first == last || s.charAt(first) == s.charAt(last) ){
//return isPalindrome(s.substring(first, last));
return isPalindrome(s.substring(first, last)) == true;
//isPalindr = false;
}
else{
return isPalindrome(s.substring(first, last)) == false;
//isPalindr = true;
}
}
return isPalindr;
}
如果有人可以帮助我修改逻辑,我认为这将得到修复:)。
答案 0 :(得分:3)
删除与问题无关的所有代码使我们留下:
public static boolean isPalindrome(String s){
for loop {
isPalindrome();
}
}
isPalindrome调用isPalindrome调用isPalindrome等...无限。
这与正确的递归函数之间的区别在于递归函数将具有某种条件语句,从而打破调用自身的函数的循环。执行流程将如下所示:
isPalindrome(1) begins execution and calls isPalidrome(2)
isPalindrome(2) begins execution and calls isPalidrome(3)
isPalindrome(3) begins execution and calls isPalidrome(4)
isPalindrome(4) begins execution and calls isPalidrome(5)
isPalindrome(5) begins execution and returns to isPalindrome(4)
isPalindrome(4) resumes execution and returns to isPalindrome(3)
isPalindrome(3) resumes execution and returns to isPalindrome(2)
isPalindrome(2) resumes execution and returns to isPalindrome(1)
isPalindrome(1) resumes execution and returns.
如果这个解释没有帮助,那么就这样想吧。假设有人一次一个地递给你盘子,看看你是否可以一次拿25个盘子。它会是这样的:
Plate 1 is given to you. Are there 25 plates? No. Add another plate.
Plate 2 is stacked on top of Plate 1. Are there 25 plates? No. Add another plate.
Plate 3 is stacked on top of Plate 2. Are there 25 plates? No. Add another plate.
...
Plate 24 is stacked on top of Plate 23. Are there 25 plates? No. Add another plate.
Plate 25 is stacked on top of Plate 24. Are there 25 plates? Yes. Mission Accomplished. Now, let's put the plates back.
Plate 25 is removed.
Plate 24 is removed.
...
Plate 3 is removed.
Plate 2 is removed.
Plate 1 is removed.
以下是如何编码:
bool stackPlates(int i){
plateStack.addPlate();
if (plateStack.wasDropped == true) { return false; } // Were the plates dropped? Return FALSE to indicate failure.
else if (i < 25) { return stackPlates(i+1); } // Are there 25 plates yet? If not, add another.
else { return true; } // There are 25 plates stacked. Return TRUE to indicate success.
plateStack.removePlate(i);
}
这是从另一个函数调用的stackPlates(int i):
bool success = stackPlates(1);
if (success==TRUE) { cout << "CONGRATULATIONS! YOU STACKED 25 PLATES!"; }
else { cout << "YOU BROKE THE PLATES! BETTER LUCK NEXT TIME!"; }
为了正常工作,您的功能需要做的是:
bool isPalindrome(string s, int i) {
char first = s[i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
char last = s[(s.length -1) -i]; // REPLACE THIS WITH THE CODE TO SKIP SPACES & SPECIAL CHARACTERS
if ( first != last ) { return false; } // return false if mismatch letter
else if ( i >= (s.length/2) ) { return true; } // return true if string fully checked
else { return isPalindrome(s, i+1); } // string not fully checked; move to next letter
}
答案 1 :(得分:2)
你遇到了堆栈溢出,因为函数底部的else分支是在(第一个&lt; = last&amp;&amp;&amp;“字符等于”)时执行的,所以你继续在你的字符串是的情况下重复出现由一个角色组成。
顺便说一句,我认为你的代码并没有干净地使用递归:你应该在开始重复使用字符串之前预处理你的字符串一次,执行回文递归的代码应该简单得多。
答案 2 :(得分:1)
对于任何给定的isPalindrome条目,它会以递归方式调用自身,因为你的其他条件没有条件。所以,如果它满足标准“first&gt; last || s.charAt(first)!= s.charAt(last)”,它将递归调用isPalindrome,那么下一次调用也是如此,即使它击中了else
我不知道Palindrome是什么或问题的真正解决方案是什么,但这就是你得到堆栈溢出错误的原因。我怀疑你需要为你的其他人添加另一个条件,以便它会停止递归调用自己。
答案 3 :(得分:0)
在编写递归函数时,最好的方法是通常决定一个基本情况(:“像”是一个回文,尽管是“a”......)然后设计一个方法来接受任何一个陈述并将其移至基本案例。
所以在回文的情况下,它与以前的基本思想相同,如果第一个字符和最后一个字符是相同的,则返回true并检查字符串的其余部分(因此更接近基本情况)和如果他们不是那么你就会返回假。
你的堆栈溢出来自于在每种情况下调用isPalindrome,而不是当你需要继续解决问题时,不要忘记如果两个字符意味着某些东西不是回文,那么其余部分就会变得无关紧要了(因此不需要)不会被递归)
答案 4 :(得分:0)
您的重新编码版本有点奇怪,因为它在不需要时仍然使用循环。特别是,您的代码永远不会超出循环中的第一次迭代,因为在嵌入式if-else
语句中,无论如何都会返回结果,因此您的函数将始终在第一次迭代期间退出(除非根本没有迭代。)
应该接近递归
你正确处理的基本情况;任何长度为1或更短的字符串都自动成为回文结构。
下一步是考虑一个更大的问题,也许是一些字符串abcwewe....ba
。我们怎样才能将其分解为一个更简单的问题?我们知道我们通常会检查字母是否是回文,从头开始逐个检查字母,但后来我们也意识到每次检查字母时,我们再次重复同样的问题并解决同样的方式。
在我上面给出的字符串中,我们检查并确认第一个字母a
与最后一个字母a
相同,这是一种部分解决方案。现在我们最终得到的是较小的单词bcwewe....b
,再次出现同样的问题:这个新的字符串也是一个回文吗?
因此,你现在要做的就是调用递归调用,但这次使用以第二个字符开头的子字符串到第二个到最后一个字符。您只需两行编写答案,如下所示:
public static boolean isPalindrome(String s) {
if (s.length() <= 1) return true; // base case
return s.charAt(0) == s.charAt(s.length()-1) && isPalin(s.substring(1,s.length()-1)); // recursive case
}
需要注意的一点是我正在使用短路&&
,所以如果第一个条件失败(检查第一个和最后一个字符),那么Java将不会调用递归。