I have been messing around with recursion today. Often a programming technique that is not used enough.
I set out to recursively reverse a string. Here\'s what I cam
In Java, since the String is immutable, the String concatenation would be more complex than it looks like.
For every concatenation, it creates a new string copying the contents of original String resulting in a linear complexity O(n) where n is the length of the string, so for m such operations it is O(m*n), we can say it is of quadratic complexity O(n^2).
We can use a StringBuilder which has O(1) complexity for each append. Below is the recursive program using StringBuilder. This uses only n/2 stack frames, so it has less space complexity than the normal recursive call which would be like 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);
}
}
You don't want to nest too deeply. Divide-and-conquer is the way to go. Also reduces total size of temporary strings and is amenable to parallelisation.
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))
);
}
(Not tested - this is stackoverflow.)
String.concat
instead of +
would improve performance at the expense of clarity.
Edit: Just for fun, a tail-recursion friendly version of the naive algorithm.
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))
);
}
Correct handling of surrogate pairs is left to the interested reader.
You capture the basic idea, but extracting the last character doesn't improve clarity. I'd prefer the following, others might not:
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));
}
}
This is what I've found to work and use recursive. You can pass str.length()
as strLength argument
private static String reverse(String str, int strLength) {
String result = "";
if(strLength > 0)
result = str.charAt(strLength - 1) + reverse(str, strLength - 1);
return result;
}
If you think less code is good then....
static String reverse(String str){
return str.length()>=2 ? str.charAt(str.length()-1) + reverse(str.substring(0,str.length()-1)) : str ;
}
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 "";
}