【问题标题】:Whats the best way to recursively reverse a string in Java?在Java中递归反转字符串的最佳方法是什么?
【发布时间】:2010-10-25 23:09:34
【问题描述】:

我今天一直在搞递归。通常是一种未被充分使用的编程技术。

我开始递归地反转一个字符串。这是我想出的:

//A method to reverse a string using recursion
    public String reverseString(String s){
        char c = s.charAt(s.length()-1);
        if(s.length() == 1) return Character.toString(c);   

        return c + reverseString(s.substring(0,s.length()-1));
    }

我的问题:Java 中有没有更好的方法?

【问题讨论】:

    标签: java recursion string


    【解决方案1】:

    最好的方法是不使用递归。这些东西通常用于教授学生递归概念,而不是实际的最佳实践。所以你这样做的方式很好。只是不要在 Java 中将递归用于现实世界应用程序中的这类东西;)

    附言。除了我刚才所说的,我会选择 "" 作为递归函数的基本情况:

    public String reverseString(String s){
        if (s.length() == 0) 
             return s;
    
        return reverseString(s.substring(1)) + s.charAt(0);
    }
    

    【讨论】:

    • 如果我错了,请纠正我,但我相信 Mehrdad 只是指像这样的微不足道的情况。尽管与迭代解决方案相比,递归解决方案实际上可能更容易想到,但我相信它会占用更多的“堆栈”来执行递归。在反转字符串的情况下,为什么在根本没有必要的情况下要进行递归解决方案?基本上在你绝对需要的情况下使用递归。
    • 这需要一大堆
    【解决方案2】:

    如果你要这样做,你想对一个字符数组进行操作,因为字符串是不可变的,如果你这样做,你将在整个地方复制字符串。

    这是未经测试的,完全是意识流。它可能在某处有一个OB1。而且非常不是 Java。

    public String reverseString(String s)
      {
      char[] cstr = s.getChars();
      reverseCStr(cstr, 0, s.length - 1);
    
      return new String(cstr);
      }
    
    /**
     * Reverse a character array in place.
     */
    private void reverseCStr(char[] a, int s, int e)
      {
      // This is the middle of the array; we're done.
      if (e - s <= 0)
        return;
    
      char t = a[s];
      a[s] = a[e];
      a[e] = t;
      reverseCStr(a, s + 1, e - 1);
      }
    

    【讨论】:

    • 是的,我知道使用字符串的 C/C++ 类似方式,我对 Java 实现更感兴趣,但我确实喜欢相比之下它的效率。
    • 嗯,这个用Java写的。它只是不是一种 Java 式的做事方式。在任何情况下,我都不会在 Java C 中递归地执行此操作,因此将 C 写到 Java 中并没有应有的错误。
    【解决方案3】:

    你不想嵌套太深。分而治之是要走的路。还减少了临时字符串的总大小,并且可以并行化。

    public static String reverseString(String str) {
        int len = str.length();
        return len<=1 ? str : (
            reverseString(str.substring(len/2))+
            reverseString(str.substring(0, len/2))
        );
    }
    

    (未测试 - 这是 stackoverflow。)

    String.concat 而不是+ 会以清晰度为代价提高性能。

    编辑:只是为了好玩,朴素算法的尾递归友好版本。

    public static String reverseString(String str) {
        return reverseString("", str);
    }
    private static String reverseString(String reversed, String forward) {
        return forward.equals("") ? reversed : (
             reverseString(reversed+forward.charAt(0), forward.substring(1)) 
        );
    }
    

    代理对的正确处理留给感兴趣的读者。

    【讨论】:

    • 差别不大...仍然是 O(n) 操作(假设字符串连接为 O(1) 操作)。它只是看起来更像 MergeSort 和其他东西,但事实并非如此。唯一的好处是——正如你所描述的——递归树的深度。
    • 串联是 O(n)(对于足够大的 n)。
    • 我认为,我的方法给出 O(n log n) 临时字符串字符,而线性方法给出 O(n^2)。
    • 两者都给出 O(n) 个临时字符串。
    • 第二种方法在这部分有错误reversed+forward.charAt(0),应该是forward.charAt(0) + reversed。但是它很容易给出OutOfMemoryError: Java heap space 错误。
    【解决方案4】:

    这是我工作正常的递归反向函数

    public static String rev(String instr){
        if(instr.length()<=1){
            return instr;
        } else {
           return (instr.charAt(instr.length()-1)+rev(instr.substring(0,instr.length()-1)) );
        }       
    }
    

    【讨论】:

      【解决方案5】:

      顺便说一句,这里有一个使用StringBuilder 的尾递归方法(通常建议使用Strings)。

      public String reverseString(String s_) {
          StringBuilder r = new StringBuilder();
          StringBuilder s = new StringBuilder(s_);
          r = reverseStringHelper(r, s);
          return r.toString();
      }
      private StringBuilder reverseStringHelper(StringBuilder r, StringBuilder s) {
          if (s.length() == 0)
              return r;
          else
              return reverseStringHelper(r.append(s.charAt(0)), s.deleteCharAt(0));
      }
      

      未经测试,我已经很多年没有接触过Java了,但这应该是正确的。

      【讨论】:

      • 我喜欢它,非常酷 :-) 当然,我们都可以很懒惰并使用 StringBuilder 反向方法,但其中的递归呢?!哈哈
      • 如果 StringBuilder 的(常见实现)使用 off+len(或类似的)而不是仅仅使用 len,效果会更好。另外,我没有看到您的返回值的意义。
      • @Tom:假装这些方法返回新对象而不是就地变异,让它感觉更实用;)
      【解决方案6】:

      如果您正在编写真正的代码(不是学习递归),请使用 StringBuilder 的 reverse() 方法。 Java Tutorial 给出了这个例子:

      String palindrome = "Dot saw I was Tod";   
      StringBuilder sb = new StringBuilder(palindrome);
      sb.reverse();  // reverse it
      System.out.println(sb);
      

      【讨论】:

        【解决方案7】:

        这取决于您对“更好”的定义。 :-) 说真的,不过;您的解决方案本质上使用了最大递归深度;如果堆栈大小与您对“更好”的定义有关,那么您最好使用以下内容:

        public String reverseString(String s) {
           if (s.length() == 1) return s;
           return reverseString(s.substring(s.length() / 2, s.length() -1) + reverseString(0, s.length() / 2);
        }
        

        【讨论】:

        • 啊,我明白了。这种本质上将问题减半并将基本情况应用于问题的每一半的方法是“从递归中获得最佳效果”的常用方法吗?
        • 好吧,就像我说的,这就是你定义“更好”的方式。这种方法并没有明显更快,但是使用这种方法获得的最高递归深度(因此也是最大的堆栈)是 log(s.length()),而使用最初提出的方法,递归的最高深度你得到的是 s.length()。这种方式会节省一点堆栈大小。
        • 看起来你有一个流浪的 -1,缺少子字符串和其他一些东西在那很长的行中发生。它不适用于“”。
        • @tom:这只是伪代码。我不是在为 OP 编写解决方案;只是提供一个建议并快速了解我在说什么。
        【解决方案8】:

        这是我发现的工作和使用递归。您可以将str.length() 作为 strLength 参数传递

        private static String reverse(String str, int strLength) {
            String result = "";
            if(strLength > 0)
                result = str.charAt(strLength - 1) + reverse(str, strLength - 1);
            return result;
        }
        

        【讨论】:

          【解决方案9】:

          在 Java 中,由于 String 是不可变的,因此 String 连接会比看起来更复杂。

          对于每个连接,它会创建一个复制原始字符串内容的新字符串,从而导致线性复杂度 O(n) 其中 n 是字符串的长度,所以对于m个这样的操作是O(m*n),我们可以说它是二次复杂度O(n^2)

          我们可以使用 StringBuilder,它对每个追加都有 O(1) 复杂度。下面是使用 StringBuilder 的递归程序。这仅使用 n/2 堆栈帧,因此它的空间复杂度比普通递归调用要小,如 s.charAt(s.length-1) + reverse(s.subString(0, s.length-2);

          public class StringReverseRecursive {
              public static void main(String[] args) {
                  String s = "lasrever gnirts fo noitatnemelpmi evisrucer a si sihT";
                  StringBuilder sb = new StringBuilder(s);
                  reverse(s, sb, 0, sb.length() - 1);
                  System.out.println(sb.toString());
              }
          
              public static void reverse(String s, StringBuilder sb, int low, int high) {
                  if (low > high)
                      return;
                  sb.setCharAt(low, s.charAt(high));
                  sb.setCharAt(high, s.charAt(low));
                  reverse(s, sb, ++low, --high);
              }
          }
          

          【讨论】:

            【解决方案10】:

            这绝对是我递归反转字符串的方式(尽管在您的条件下将它扩展到空字符串的情况可能会很好。)我认为没有任何根本上更好的方法。

            编辑:对字符数组进行操作并在递归链中传递一个“截止”长度可能更有效,如果你明白我的意思,而不是制作子字符串。然而,这并不值得吹毛求疵,因为它本来就不是一种非常有效的技术。

            【讨论】:

              【解决方案11】:

              您捕获了基本概念,但提取最后一个字符并不能提高清晰度。我更喜欢以下内容,其他人可能不会:

              public class Foo
              {
                  public static void main(String[] argv) throws Exception
                  {
                      System.out.println(reverse("a"));
                      System.out.println(reverse("ab"));
                      System.out.println(reverse("abc"));
                  }
              
              
                  public final static String reverse(String s)
                  {
                      // oft-repeated call, so reduce clutter with var
                      int length = s.length();
              
                      if (length <= 1)
                          return s;
                      else
                          return s.substring(length - 1) + reverse(s.substring(0, length - 1));
                  }
              }
              

              【讨论】:

                【解决方案12】:

                正如Mehrdad 所说,最好不要使用递归。但是,如果您确实使用它,您不妨保留每次调用的第一个和最后一个字符,从而将递归调用的数量减半。也就是说,

                public String reverseString(String s){
                    int len = s.length();
                
                    if (len <= 1) {
                        return s;
                    }
                
                    char fst = s.charAt(0);
                    char lst = s.charAt(len - 1);
                
                    return lst + reverseString(s.substring(1, len - 2)) + fst;
                }
                

                这也处理空字符串的情况。也许传递具有适当容量的 StringBuilder 会加快速度,但这留给读者作为练习;)

                【讨论】:

                • 例如,这在字符串“a”上失败。为什么比原版好?
                • s/==/
                • 我喜欢它,因为它将递归堆栈减半,但如前所述,它不适用于像“a”这样的字符串。也许可以将这种方法与上面的尾递归一起使用,首先验证字符串然后应用递归。正如我所看到的,您理解如果您反转一个字符的字符串,没有人会关心,因为反过来是一样的。我的假设是对的吗?
                • 我不知道为什么更正后的版本不适用于“a”:它的长度为 1,因此返回原样。我想我不明白你最后的话。
                【解决方案13】:

                您可以尝试使用外部变量,并将所有字符 1 1 相加:

                    public static String back="";
                
                public static String reverseString(String str){
                
                
                    if(str.length()==0){
                
                        return back;
                
                    }else {
                
                        back+=str.charAt(str.length()-1);
                
                        lees(str.substring(0,str.length()-1));
                
                
                        return back;
                
                    }
                

                }

                【讨论】:

                • 我想我在第一次尝试中确实尝试过这样的事情。
                【解决方案14】:

                Here 是我的不可变版本:

                 String reverse(String str) {
                    if(str.length()<2) return str;
                    return  reverse(str.substring(1)) +str.charAt(0);
                }
                

                和尾递归版本:

                 String reverseTail(String str) {
                    if(str.length()<2) return str;
                    return str.charAt(str.length()-1)+ reverseTail(str.substring(0,str.length()-1));
                

                【讨论】:

                  【解决方案15】:

                  在这种情况下,这是完全没有必要的,但如果您自己制作堆栈,则可以模拟递归并避免递归深度问题。

                  您可以迭代实现递归,这在您拥有本质上是递归的算法时可能是必要的,但也需要针对大问题运行它们。

                  String recIterReverse (String word){
                  
                      Stack <String> stack = new Stack <String> ();
                      stack.push(word);
                      String result = "";
                  
                      while (!stack.isEmpty()){
                          String temp = stack.pop();
                          result = temp.charAt(0) + result;
                  
                          if (temp.length() > 1){
                          stack.push(temp.substring(1));
                          }
                      }
                  
                      return result;
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    函数调用:

                        //str:string to be reversed,i=0,j=str.length-1
                    
                    
                        public void reverseString(String str,int i,int j)
                        {
                    
                         if(i==j)
                            {
                             System.out.println(str);
                             return;
                            }
                    
                         char x=str.charAt(i);
                         str=str.replace(str.charAt(i),str.charAt(j));
                         str=str.replace(str.charAt(j),x);
                         i++;j--;
                         reverseString(str,i,j);
                        }
                    

                    这个方法也有效..

                    【讨论】:

                      【解决方案17】:

                      尝试以下方法:

                      public class reverse2
                      {
                          public static void main(String name)
                          {
                          String revname=new StringBuffer(name).reverse().toString();
                          System.out.println("original string " + name + " and the reverse of it is " + revname);
                          }
                      }
                      

                      【讨论】:

                        【解决方案18】:
                        public static String rev(String name){
                            if(name.length()>=1){
                            System.out.print(name.charAt(name.length()-1)); 
                            return rev(name.substring(0,name.length()-1));
                            }
                            else{
                                return ""+name.substring(0);
                            }
                        }
                        

                        【讨论】:

                          【解决方案19】:
                          String rev="";
                          
                          public String reverseString(String s){
                                  if (s.length()==0) return "";
                                  return rev+s.substring(s.length()-1,s.length())+reverseString(s.substring(0, s.length()-1));
                              }
                          

                          【讨论】:

                            【解决方案20】:
                            public String reverseString (String s) {
                            
                                if (s != null && s.length () > 0 ) {
                                    rev = rev + s.substring (s.length () - 1);
                                    reverseString (s.substring (0, s.length () - 1));
                                }
                                return rev;
                            
                            }
                            

                            【讨论】:

                              【解决方案21】:
                              public class StringUtility {
                              
                              public static void main(String[] args) {
                                  StringUtility stringUtility = new StringUtility();
                              
                                  String input = "santosh123";
                                  int middle = input.length() / 2;
                                  middle = middle - 1;
                                  System.out.println(stringUtility.stringReverse(input, middle));
                              }
                              
                              public String stringReverse(String input, int middle) {
                              
                                  if (middle == -1) {
                              
                                      System.out.println("if");
                                      return input;
                              
                                  } else {
                              
                                      System.out.println("else");
                                      input = swapChar(input, middle);
                                      middle = middle - 1;
                                      return stringReverse(input, middle);
                              
                                  }
                              
                              }
                              
                              private String swapChar(String input, int middle) {
                                  StringBuilder str = new StringBuilder(input);
                                  char begin = str.charAt(middle);
                                  int endIndex = input.length() - middle - 1;
                                  char end = str.charAt(endIndex);
                                  str.setCharAt(middle, end);
                                  str.setCharAt(endIndex, begin);
                                  System.out.println(str + "  " + middle + "  " + endIndex);
                                  return str.toString();
                              }
                              
                              }
                              

                              【讨论】:

                                【解决方案22】:

                                如果你认为代码越少越好......

                                static String reverse(String str){
                                    return str.length()>=2 ? str.charAt(str.length()-1) + reverse(str.substring(0,str.length()-1)) : str ;
                                }
                                

                                【讨论】:

                                  【解决方案23】:

                                  已经有大约 20 个答案,但我也将加入我的递归算法。它可能有点冗长,但至少是可读的。

                                  public static String reverseString(String str) {
                                     return reverseString("", str);
                                  }
                                  
                                  private static String reverseString(String result, String original) {
                                     if (original.length() == 0) {
                                        return result;
                                     } else {
                                        int length = original.length();
                                        String lastLetter = original.substring(length - 1, length);
                                        original = original.substring(0, length - 1);
                                        return reverseString(result + lastLetter, original);
                                     }
                                  }
                                  

                                  代码基本上递归地获取字符串的末尾并将其移到前面。例如,如果我们要反转的字符串是“jam”,那么每次调用辅助方法时,结果和原始字符串如下:

                                  // result:  original:
                                  // ""       jam
                                  // m        ja
                                  // ma       j
                                  // maj      ""
                                  

                                  【讨论】:

                                    【解决方案24】:

                                    使用递归方法调用反转字符串。

                                    示例代码

                                    public static String reverseString(String s) {
                                        if (s.length() == 0) {
                                            return s;
                                        }
                                        else {
                                            return s.charAt(s.length() - 1) + reverseString(s.substring(0, s.length() - 1));
                                        }
                                    }
                                    

                                    【讨论】:

                                    • 能否请您添加一些解释,为什么这是最好的方法?
                                    【解决方案25】:

                                    这是我的解决方案,我在上面的许多解决方案中看到我们正在获取字符串长度,但理想情况下我们不需要它。 Zen 是使用递归,只需将字符串的第一个字符切掉,然后将其余的传递给递归方法。耶!!我们得到了解决方案。

                                    private static void printReverse(String str) {
                                                if (!str.isEmpty()) {
                                                    String firstChar = str.substring(0, 1); //Get first char of String
                                                    String newstr = str.substring(0, 0) + str.substring(1); // Get remaining string
                                                    printReverse(newstr); // Recursion magic
                                                    System.out.print(firstChar); //Output
                                                }
                                            }
                                    

                                    【讨论】:

                                      【解决方案26】:
                                      public static String reverse(String s){
                                      
                                          int n = s.length()-1;
                                      
                                          if(n >=0)
                                          return  s.substring(s.length()-1)+ReverseString(s.substring(0,n--));
                                          else return "";
                                      }
                                      

                                      【讨论】:

                                        猜你喜欢
                                        • 1970-01-01
                                        • 2021-06-25
                                        • 2011-01-27
                                        • 2012-03-04
                                        • 1970-01-01
                                        • 2019-05-12
                                        • 1970-01-01
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多