Java-使用递归从字符串创建所有子字符串

Java-使用递归从字符串创建所有子字符串,java,recursion,Java,Recursion,以下Java代码使用递归从字符串创建所有可能的子字符串。 我想知道有没有更好的编码方法?我想使用递归 public class main { public static void main(String[] args) { generate("hello"); } public static void generate(String word) { if (word.length() == 1) { System

以下Java代码使用递归从字符串创建所有可能的子字符串。 我想知道有没有更好的编码方法?我想使用递归

public class main {

    public static void main(String[] args) {
        generate("hello");
    }

    public static void generate(String word) {
        if (word.length() == 1) {
            System.out.println(word);
            return;
        }else{
            System.out.println(word);
            generate(word.substring(0, word.length()-1)); 
            generate(word.substring(1, word.length())); 
        }

    }

}
常见问题 为什么我要使用递归来实现这一点? 因为StackOverflow的首席执行官说递归很重要

此问题有重叠的子问题,因此自上而下的递归没有多大效果。您正在多次计算多个子字符串

实际上,它是非常无效的(我猜是O(2^n))。试着在长一点的字符串上运行它

generate("OverlappingSubproblems");
如果您对解决此问题的更好方法感兴趣,可以尝试以下方法:

public static void generate2(String word) {
    for (int from = 0; from < word.length(); from++) {
        for (int to = from + 1; to <= word.length(); to++) {
            System.out.println(word.substring(from, to));
        }
    }
}
publicstaticvoidgenerate2(字符串字){
for(int from=0;from对于(int-to=from+1;to,从Honza的答案中可以学到很多东西。我建议您尝试将其重写为递归算法

与任何递归方法一样,将其划分为自引用子问题:

1. substrings(X) = substrings_starting_at_first_character(X) + substrings(X minus first char).
2. substrings_starting_at_first_character(X) = X + substrings_starting_at_first_character(X minus last char).
接下来,找出非自参考的基本情况:

1. substrings("") = empty set.
2. substrings_starting_at_first_character("") = empty set.

从这里开始。

以下是最好的解决方案:

public class recursive {

    static String in = "1234";

    public static void main(String[] args) {
        substrings(0,1);
    }

    static void substrings(int start, int end){
        if(start == in.length() && end == in.length()){
            return;
        }else{
            if(end == in.length()+1){
                substrings(start+1,start+1);
            }else{
                System.out.println(in.substring(start, end));
                substrings(start, end+1);
            }
        }
    }

}
它首先检查基本情况:开始和结束是否都等于in.length()。 因为如果是,这意味着没有更多的子字符串可以找到,程序结束

让我们从start=0和end=1开始。它们在.length()中显然不相等,end在.length()中肯定不等于+1。 因此,子字符串(0,1)将被打印出来,即1。 子字符串的下一次迭代将是子字符串(0,2),而in.子字符串(0,2)将被打印,即12。这将持续到end==in.length()+1,当程序完成子字符串(0,4)并尝试移动到子字符串(0,5)时会发生这种情况。 5==in.length()+1,因此当发生这种情况时,程序将执行子字符串(start+1,start+1),即子字符串(1,1)。该过程将继续执行子字符串(1,2)和(1,3),直到(1,5)程序将运行子字符串(2,2)

所有这些都将继续,直到子字符串(4,4),此时程序停止

结果如下所示:

public static void generate2(String word) {
    for (int from = 0; from < word.length(); from++) {
        for (int to = from + 1; to <= word.length(); to++) {
            System.out.println(word.substring(from, to));
        }
    }
}
一, 12 123 1234

二, 23 234

三, 三十四


4

另一种干净的方法-同时使用循环和递归(并且没有重叠问题)

公共静态void打印组合(字符串首字母、字符串组合){
系统输出打印(组合+“”);
对于(int i=0;i
输出为-112123412345123512451245125131345135141452152232345234523452452533434535455

公共类子序列fstr{
 //substring all the words from a string
  public class RecSubstring
  {
    static int c=0; 
    static void rec(String str)
    {
      if(str.equals(""))
        return;
      else
      {
        c=str.indexOf(' ');  
        System.out.println(str.substring(0,c));
        rec(str.substring(c+1));
     }
   }

  public static void main(String args[])
  {
    String st="We are Happy"+" " ;
    rec(st);
  }
 }
公共静态void main(字符串[]args){ 字符串str=“abcd”; System.out.println(“0000----”+str.length()); 线性组合(str); } 静态无效线性组合(字符串str){ 对于(int i=0;i
void allsubstring(字符串s,int start,int end)
{
如果(开始==s.size()&&end==s.size()){
返回;
}
否则{
如果(end==s.size()){
所有子字符串(s,开始+1,开始+1);
}
否则{

cout使用递归的另一种方法

    public static void main(String[] args) 
    {
        subStrings("ABCDE");        
    }
    
    static void subStrings(String str) 
    {
        if(str.length()==0)
        {
            return;
        }
        subString(str);
        subStrings(str.substring(1,str.length()));
        
    }
    
    private static void subString(String str)
    {
        if(str.length()==1)
        {
            System.out.print(str+" ");
            return;
        }
        
        System.out.print(str+" ");
        subString(str.substring(0,str.length()-1));
        
    }
 

你想使用递归,并且你有一个使用递归的工作解决方案?我看不出问题所在。看起来像那种性质的递归程序一样高效和干净。你的方法很好,但另一种递归方法和我的想法是,因为你的子字符串是主字符串的单个连续片段,你e处理两个整数变量:起始位置和结束位置。因此,你基本上是在寻找它们的组合。例如,使用“Hello”长度为5时,起始/结束位置为:1/5、2/5、3/5、4/5、1/4、2/4、3/4,etc@Kayaman,是的,我有一个有效的解决方案,只是想看看是否有更好的方法,我不是递归专家。@Marko,是的,我意识到递归不适合Java,只是想练习递归技能,因为这不是解决方案您也发布了n^2?是的,它是n^2,但另一个解决方案是2^n。啊,这两个解决方案之间混淆了。此解决方案不会生成字符串中所有可能的字符组合。我们正在寻找未解释组合的子字符串。您能解释解决方案的时间和空间复杂性吗?是否为O(nlogn)对于time?System.out.println(in.substring(start,end));--这一行在start=end时打印空字符串。它应该仅在start!=end时执行,类似于
if(start!=end){System.out.println(str.substring(start,end));}
14,15,…不是子字符串。您的解决方案是给出可以使用字符串中的字符进行的所有组合。。。
void allsubstring(string s,int start,int end)
{
if(start == s.size() &&  end == s.size()) {
    return;
}
else {
    if(end == s.size()) {
        allsubstring(s,start+1,start+1);
    }
    else {
        cout<<s.substr(start,end-start+1)<<endl;
        allsubstring(s,start,end+1);
    }
}
    public static void main(String[] args) 
    {
        subStrings("ABCDE");        
    }
    
    static void subStrings(String str) 
    {
        if(str.length()==0)
        {
            return;
        }
        subString(str);
        subStrings(str.substring(1,str.length()));
        
    }
    
    private static void subString(String str)
    {
        if(str.length()==1)
        {
            System.out.print(str+" ");
            return;
        }
        
        System.out.print(str+" ");
        subString(str.substring(0,str.length()-1));
        
    }