web-dev-qa-db-fra.com

Quel est le meilleur moyen d'inverser récursivement une chaîne en Java?

Je m'amuse avec la récursion aujourd'hui. Souvent, une technique de programmation qui n'est pas assez utilisée.

Je me suis mis à inverser récursivement une chaîne. Voici ce que je suis venu avec:

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

Ma question: existe-t-il une meilleure solution en Java?

24
binarycreations

Le meilleur moyen est de ne pas utiliser la récursivité. Ces éléments sont généralement utilisés pour enseigner aux étudiants le concept de récursivité, et non les meilleures pratiques actuelles. Donc, la façon dont vous le faites est très bien. N'utilisez simplement pas la récursivité en Java pour ce genre de choses dans les applications du monde réel;)

PS. Mis à part ce que je viens de dire, je choisirais "" comme scénario de base de ma fonction récursive:

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

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

Si vous voulez faire cela, vous voulez opérer sur un tableau de caractères, car une chaîne est immuable et vous allez copier des chaînes partout si vous le faites de cette façon.

Ceci est non testé et totalement courant de conscience. Il a probablement un OB1 quelque part. Et très pas 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);
  }
9
Adam Jaskiewicz

Vous ne voulez pas nicher trop profondément. Diviser pour régner est la voie à suivre. Réduit également la taille totale des chaînes temporaires et permet la parallélisation.

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

(Non testé - il s'agit de stackoverflow.)

String.concat au lieu de + améliorerait les performances au détriment de la clarté.

Edit: Juste pour le plaisir, une version conviviale de l’algorithme naïf pour la récursion de queue.

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

Le traitement approprié des paires de substitution est laissé au lecteur intéressé.

7

voici ma fonction inverse récursive qui fonctionne bien

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

Juste pour le plaisir, voici une méthode récursive utilisant StringBuilder (qui est généralement recommandée pour la manipulation de 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));
}

Non testé, je n'ai pas traité Java depuis de nombreuses années, mais cela devrait être à peu près correct.

2
ephemient

Si vous écrivez du vrai code (sans apprendre la récursion), utilisez la méthode StringBuilder reverse (). Le Java Tutorial donne cet exemple:

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

Cela dépend de ce que vous définissez comme "meilleur". :-) Sérieusement; votre solution utilise essentiellement la profondeur maximale de récursivité; Si la taille de la pile vous préoccupe par votre définition de "mieux", vous feriez mieux d'utiliser quelque chose comme ceci:

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);
}
1
Paul Sonier

C'est ce que j'ai trouvé pour fonctionner et utiliser récursif. Vous pouvez passer str.length() comme argument 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;
}
1
Randy Turner

appel de fonction:

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

cette méthode fonctionne aussi ..

0
amit_183
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));
    }
0
Souji

Si vous pensez que moins de code est bon, alors .... 

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

Il y a déjà environ 20 réponses, mais je vais aussi ajouter mon algorithme récursif. C'est peut-être un peu verbeux mais c'est au moins lisible. 

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

Le code prend essentiellement de manière récursive la fin de la chaîne et la déplace au premier plan. Par exemple, si la chaîne que nous voulons inverser est "jam", à chaque appel de la méthode d'assistance, les chaînes de résultat et d'origine sont les suivantes:

// result:  original:
// ""       jam
// m        ja
// ma       j
// maj      ""
0
anita
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);
    }
}
0
Sudhanshu

Vous pouvez essayer avec une variable externe et ajouter 1 à 1 tous les caractères:

    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;

    }

}

0
JBoy

Essayez ce qui suit: 

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

Chaîne inversée utilisant l'appel de méthode récursive.

Exemple de code

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

Dans ce contexte, cela est totalement inutile, mais vous pouvez simuler la récursivité et éviter les problèmes de profondeur de récursivité si vous créez votre propre pile.

Vous pouvez effectuer une récursion itérative d'implémentation, ce qui peut s'avérer nécessaire lorsque vous utilisez des algorithmes intrinsèquement récursifs, mais que vous devez également les exécuter pour des problèmes de grande taille.

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

C'est ma solution, j'ai vu dans de nombreuses solutions ci-dessus que nous obtenons la longueur de la chaîne, mais idéalement, nous n'en avons pas besoin. Le Zen doit utiliser la récursivité, il suffit de couper le premier caractère de la chaîne et de passer le reste à la méthode récursive. Yay!! nous avons la solution. 

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
            }
        }
0
vinni

C'est certainement ce que je ferais pour inverser de manière récursive une chaîne (même s'il serait peut-être agréable de l'étendre au cas d'une chaîne vide dans votre état.) Je ne pense pas qu'il y ait de manière fondamentalement meilleure.

EDIT: Il peut être plus efficace d’opérer sur un tableau de caractères et de passer une "longueur de coupure" dans la chaîne de récursion, si vous obtenez ma dérive, plutôt que de créer des sous-chaînes. Cependant, cela ne vaut pas vraiment la peine de chercher, car ce n’est pas une technique extrêmement efficace au départ.

0
mquander

Ici est ma version immuable:

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

et queue version récursive:

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

Comme Mehrdad a noté, il est préférable de ne pas utiliser la récursivité. Si vous l'utilisez, vous pouvez également conserver le premier et le dernier caractère de chaque appel, divisant ainsi le nombre d'appels récursifs par deux. C'est,

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

Cela gère également le cas de la chaîne vide. Peut-être que passer par un StringBuilder avec la capacité appropriée accélèrerait encore les choses, mais cela reste un exercice pour le lecteur;)

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

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

}
0
Vishal Akkalkote

Vous capturez l'idée de base, mais extraire le dernier caractère n'améliore pas la clarté. Je préférerais les suivantes, d'autres pourraient ne pas:

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