java stackoverflow_关于java:如何避免递归中的StackOverFlow?

我需要使用递归找到String中每个字符的频率。

在网上找到了这个问题,并希望以此作为挑战。

使用了两个变量'a'和'i',其中'a'用于将当前字符的索引存储在需要搜索的字符串中,而'i'用于遍历整个字符串以搜索 'a'已提取的字符。

查找单词中每个字符的出现频率。

import java.util.*;

public class ini {

public static void main(String args[]) {

recur(0, 0,"Hello how are you", 0);

}

static private char m = ' ';

private static boolean recur(int a, int i, String s, int count) {

if (s.length() >= 1) {

if (a < s.length()) {

m = s.charAt(a);

if (i < s.length()) {

if (s.charAt(a) == s.charAt(i)) {

count += 1;

}

recur(a, ++i, s, count);

}

i = 0;

System.out.println(s.charAt(a) +":" + count);

s = s.replaceAll(Character.toString(s.charAt(a)),"");

a += 1;

count = 0;

}

if (a != s.length() - 1) {

recur(a, i, s, count);

}

} else {

return false;

}

return true;

}

}

当前输出完全忽略字母"w"

H:1

l:2

:3

o:3

r:1

y:1

Exception in thread"main" java.lang.StackOverflowError

at ini.recur(ini.java:26)

at ini.recur(ini.java:26)

at ini.recur(ini.java:26)

at ini.recur(ini.java:26)

at ini.recur(ini.java:26)

at ini.recur(ini.java:26)

at ini.recur(ini.java:26)

at...

recur(a, i, s, count)行导致它。两次调用之间的参数不会更改。它可能应该是recur(a + 1, i, s, count)

是的,我确实意识到这一点。我经常玩recur(++a, 0, s, 0),但没有得到任何结果。

@Nexevis是的,我发布的代码是我正在尝试寻找正确结果的尝试之一,因此我做到了。我同意您的观点,即递归调用之前的if & else不是一个好习惯。

也可以使用内置的API。将String.toCharArray()放入列表。然后使用Collections.frequency。

@MichielLeegwater好吧,但我在这里缺乏逻辑。它仍然不能解决以上完全排除字符w的问题。

您确定更新索引的条件正确吗?请注意,我的建议是完全避免递归。

使用一个字母的变量名会使代码难以阅读。我在猜应该是什么意思。我想读一下意思。

可能重复的stackoverflow.com/questions/6712587/

我们不知道几件事:

h和h应该仅被视为一个字符吗?

你应该算空间吗? (从编程上讲,空格是一个字符)

您是否需要改进的解决方案?

是否允许您处理初始文本?

一些观察:

您需要更好地重命名变量

您不需要静态字段

您不需要递归函数为布尔值

a仅用于字符识别,不需要增量

快速解决方案:

private static void recur(int startingIndex, int recursionIndex, String text, int count) {

if (text.length() >= 1) {

if (startingIndex < text.length()) {

char currentCharacter = text.charAt(startingIndex);

if (recursionIndex < text.length()) {

if (currentCharacter == text.charAt(recursionIndex)) {

count += 1;

}

recur(startingIndex, ++recursionIndex, text, count);

} else {

System.out.println(currentCharacter +":" + count);

text = text.replace(Character.toString(currentCharacter),"");

recur(0, 0, text, 0);

}

}

}

}

改进的解决方案:

public class Main {

public static void main(String[] args) {

recur(0,"Hello how are you", 0);

}

private static void recur(int index, String text, int count) {

if (text.length() >= 1) {

char currentCharacter = text.charAt(0);

if (index< text.length()) {

if (currentCharacter == text.charAt(index)) {

count += 1;

}

recur(++index, text, count);

} else {

System.out.println(currentCharacter +":" + count);

text = text.replace(Character.toString(currentCharacter),"");

recur(0, text, 0);

}

}

}

}

无需修改初始文本的最佳解决方案:

private static int recur(char character, String text, int index) {

if (index >= text.length()) {

return 0;

}

int count = text.charAt(index) == character? 1 : 0;

return count + recur(text, character, index + 1);

}

@ lafeo_007如果我的答案足够好,请对其进行投票并将其标记为可接受的答案。如果您还有其他疑问,请随时提问。

天哪,您的代码几乎就像Elixir一样,谢谢!我最终的解决方案将使用您的代码。我的错误被完全封装成错误的逻辑,我的递归技能并不是我能得出的最好的。可以在它们上工作,但是非常感谢@LoolKovsky!

@ lafeo_007谢谢,希望对您有所帮助。

我的方法与您的方法略有不同,但您可能会发现它很有趣。

在我的方法中,我将删除字符并检查String长度的差异。长度的变化将是字符重复的次数。其余部分在代码中进行了说明。

public class CharactersFrequency {

public static void main(String[] args) {

CharactersFrequency cF = new CharactersFrequency();

long startTime = System.currentTimeMillis();

// I generated a sting with 1000 characters from a website

cF.frequencyOfCharacters("a quick brown fox jumps over the lazy dog");

long endTime = System.currentTimeMillis();

System.out.println("Runtime:" + (endTime - startTime) +" ms");

}

private void frequencyOfCharacters(String input) {

CharactersFrequency cF = new CharactersFrequency();

cF.frequencyOfCharactersRec(input, input.charAt(0) +"");

}

public void frequencyOfCharactersRec(String input, String currentChar) {

// If only one char is left

if (input.length() <= 1) {

System.out.println(currentChar +": 1");

} else {

// Checking Initial length and saving it

int inputOldLength = input.length();

// Removing the char whose frequency I am checking

input = input.replace(currentChar,"");

// Checking new length

int inputNewLength = input.length();

// The difference between length should be the number of times that char

// repeated

System.out.println(currentChar +" :" + (inputOldLength - inputNewLength));

// In some cases after replace function the string becomes empty

// thus charAt(0) gives an error

if (inputNewLength > 0) {

frequencyOfCharactersRec(input, input.charAt(0) +"");

}

}

}

}

输出:

a : 2

: 8

q : 1

u : 2

i : 1

c : 1

k : 1

b : 1

r : 2

o : 4

w : 1

n : 1

f : 1

x : 1

j : 1

m : 1

p : 1

s : 1

v : 1

e : 2

t : 1

h : 1

l : 1

z : 1

y : 1

d : 1

g: 1

Runtime: 3 ms

我不想拒绝您的回答,但您必须记住,他针对他的特定问题询问了一个特定的问题,您想出了一个完全不同的解决方案,该解决方案无法解决最初的问题

很公平。我一直希望您的回答会被接受,因为用户说"在线找到了这个问题,并希望以此作为挑战。"所以我虽然他不介意。我已对您的回答投了赞成票,因此它将排在最前面,因为它可以准确回答用户的要求。

@Goion我写的是对的,特别是让我可以巧妙地表明我愿意采用新的方法来解决这个问题。我喜欢这种方法,但是,您提供的示例String相当多。值得一提的是,尽管您的方法很相似,但是只是您将复合代码行分解为更简单的方式!再次感谢...!

@LoolKovsky嘿,我们不能否决这个答案!

@LoolKovsky Didnt拒绝投票。无论如何,我已将字符串更改为较小的字符串,因此代码更易于阅读。

哈哈,比文字SHA更好。为了这个社区和@LoolKovsky的答案更加精确和简洁,我将他的答案标记为最终解决方案。

@Goion我们的代码无效??,!!在字符串末尾!为此必须将replaceAll()更改为replace()!

@ lafeo_007 replaceAll()采用正则表达式,因此正则表达式中具有特殊含义的字符(如?等)会将其弄乱。如果要使用全部替换,请像这样进行更改。 text.replaceAll("["+Character.toString(currentCharacter)+"]","");

让我们继续聊天中的讨论。

经过多番修补,我已经弄清楚了。基本上,您不应该增加a。这将跳过字母,从而删除a递增的行。a += 1;此外,在进行递归操作时(我努力地想起自己),您要小心如何调用所处的函数。作为最后一步(尾递归)的递归调用,由于各种原因,您将在此处进入无限循环。您需要做的就是在第一个递归调用之前添加return语句,您将像这样解决它。

import java.util.*;

public class ini {

public static void main(String args[]) {

recur(0, 0,"Hello how are you", 0);

}

static private char m = ' ';

private static boolean recur(int a, int i, String s, int count) {

if (s.length() >= 1) {

if (a < s.length()) {

m = s.charAt(a);

if (i < s.length()) {

if (s.charAt(a) == s.charAt(i)) {

count += 1;

}

//Added crucial return statement

return recur(a, ++i, s, count);

}

i = 0;

System.out.println(s.charAt(a) +":" + count);

s = s.replaceAll(Character.toString(s.charAt(a)),"");

//removed a += 1;

count = 0;

}

if (a != s.length() - 1) {

recur(a, i, s, count);

}

} else {

return false;

}

return true;

}

}

输出:

H:1

e:2

l:2

o:3

:3

h:1

w:1

a:1

r:1

y:1

这是有关尾部与头部递归的链接:尾部与头部递归

希望这对您有所帮助!

万分感谢!在看到最新的答案之后,我对代码进行了相当大的整理,删除了不必要的boolean return语句。谢谢你的链接,会看看!

虽然我们的两个代码仍然存在一个错误! Exception in thread"main" java.util.regex.PatternSyntaxException: Dangling meta character ? near index 0 ?我们的编码不能与??,!!或其他此类字符!

Np,但很有趣,我会调查一下并向您报告!


版权声明:本文为weixin_35006125原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。