繁体   English   中英

如何在递归中避免StackOverFlow?

[英]How to avoid StackOverFlow in recursion?

我需要使用递归找到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...

有几件事我们不知道:

  1. hH应该只被认为是一个字符吗?
  2. 你算这些空间吗? (从编程上讲,空间是一个角色)
  3. 您需要改进的解决方案吗?
  4. 你被允许操纵初始文本吗?

一些观察:

  1. 您需要更好地重命名变量
  2. 您不需要静态字段
  3. 您不需要将递归函数设置为布尔值
  4. 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);
}

经过多次修修补补,我已经弄明白了。 基本上你不应该增加一个。 这将跳过字母,从而删除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

这是一个关于尾部与头部递归的链接: Tail vs. Head Recursion

希望这对你有所帮助!

我的方法与你的方法略有不同,但你可能会发现它很有趣。 在我的方法中,我删除字符并检查字符串长度的差异。 长度的变化将是角色重复的次数。 休息在代码中解释。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM