什么是在Java中递归反转字符串的最佳方法?

时间:2009-05-13 18:23:51

标签: java recursion string

我今天一直在搞乱递归。通常是编程技术使用不够。

我开始以递归方式反转一个字符串。这就是我想出的:

//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中有更好的方法吗?

26 个答案:

答案 0 :(得分:51)

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

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

public String reverseString(String s){
    if (s.length() == 0) 
         return s;

    return reverseString(s.substring(1)) + s.charAt(0);
}

答案 1 :(得分:10)

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

这是未经测试的,完全是意识流。它可能在某个地方有一个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);
  }

答案 2 :(得分:7)

你不想陷得太深。分而治之是必须走的路。还可以减少临时字符串的总大小,并且可以进行并行化。

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)) 
    );
}

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

答案 3 :(得分:3)

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

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)) );
    }       
}

答案 4 :(得分:2)

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

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

答案 5 :(得分:2)

只是为了它,这是一个使用StringBuilder的尾递归方法(通常推荐使用String)。

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,但这应该是正确的。

答案 6 :(得分:1)

这是我发现的工作和使用递归。您可以将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;
}

答案 7 :(得分:1)

这取决于你定义为“更好”的内容。 :-)严肃地说,但是;您的解决方案基本上使用最大递归深度;如果堆栈大小是你对“更好”定义的关注点,那么你最好使用这样的东西:

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);
}

答案 8 :(得分:1)

在Java中,由于String是不可变的,因此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);
    }
}

答案 9 :(得分:0)

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

  

示例代码

    public function save(){   
    $this->load->library('image_lib');
    //$nama_asli = $_FILES['userfile']['name'];
    $id = $this->input->post('id',TRUE);

    $config['file_name'] = $id ;//'_'.'_'.$nama_asli;
    $config['upload_path'] = './uploads/';
    $config['allowed_types'] = 'gif|jpg|png|jpeg|bmp';
    $config['max_size'] = '100000';

    $this->load->library('upload', $config);

    $this->upload->initialize($config);
    if ( ! $this->upload->do_upload('userfile'))
    {
        $files = $this->upload->data();
        $fileNameResize = $config['upload_path'].$config['file_name'];
        $size =  array(             
                    array('name'    => 'thumb','width'  => 100, 'height'    => 100, 'quality'   => '100%')
                );
        $resize = array();
        foreach($size as $r){               
            $resize = array(
                "width"         => $r['width'],
                "height"        => $r['height'],
                "quality"       => $r['quality'],
                "source_image"  => $fileNameResize,
                "new_image"     => base_url().$r['name'].'/'.$config['file_name']
            );
        $this->image_lib->initialize($resize); 
            if(!$this->image_lib->resize())                 
            die($this->image_lib->display_errors());
        }   

        $data = array('upload_data' => $this->upload->data());      
        $get_name = $this->upload->data();
        $nama_foto = $get_name['file_name'];
        $this->mcrud->savealat($nama_foto);
        redirect('instrument/detailalat');   


    }
    else
    {   

        //Moved your code up there
    }
}   

答案 10 :(得分:0)

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

using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Hearthstone_Test
{
  public partial class Main : Form
  {
    private void timer1_Tick(object sender, EventArgs e)
    {
        var activatedHandle = GetForegroundWindow();
        if (GetForegroundWindow() == Process.GetProcessesByName("Hearthstone"));
        {
            Console.WriteLine("Not Focused");       // No window is currently activated
        }
        else 
        { 
            Console.WriteLine("Focused");
        }

        var procId = Process.GetCurrentProcess().Id;
        int activeProcId;
        GetWindowThreadProcessId(activatedHandle, out activeProcId);
    }
    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    private static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
  }
}

代码基本上递归地获取字符串的结尾并将其移到前面。例如,如果我们要反转的字符串是&#34; jam,&#34;然后每次调用helper方法时,结果和原始字符串如下:

Operator '==' cannot be applied to operands of type 'Process[]' and 'IntPtr'

答案 11 :(得分:0)

如果您认为代码较少,那么......

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

答案 12 :(得分:0)

这是我的解决方案,我在上面的许多解决方案中看到我们得到的字符串长度,但理想情况下我们不需要它。 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
            }
        }

答案 13 :(得分:0)

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();
}

}

答案 14 :(得分:0)

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;

}

答案 15 :(得分:0)

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));
    }

答案 16 :(得分:0)

函数调用:

    //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 :(得分:0)

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);
    }
}

答案 18 :(得分:0)

尝试以下方法:

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);
    }
}

答案 19 :(得分:0)

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

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

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;
}

答案 20 :(得分:0)

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));

答案 21 :(得分:0)

您可以尝试使用外部变量,并逐个添加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;

    }

}

答案 22 :(得分:0)

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

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));
    }
}

答案 23 :(得分:0)

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会加快速度,但这仍然是读者的练习;)

答案 24 :(得分:0)

这肯定是我如何递归地反转一个字符串(尽管在你的条件下将它扩展到空字符串的情况可能会很好。)我认为没有任何从根本上更好的方法。

编辑:如果你得到我的漂移,而不是制作子串,那么对字符数组进行操作并在递归链上传递“截止”长度可能更有效。然而,这并不值得挑剔,因为它首先不是一种非常有效的技术。

答案 25 :(得分:-1)

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 "";
}
相关问题