A in-place recursive solution to reverse a string

时间:2019-04-16 23:36:07

标签: python algorithm

I am learning recursion basics from leetcode's featured tutorial Recursion I

The first exercise is to reverse a string Reverse String - LeetCode

Write a function that reverses a string. The input string is given as an array of characters char[].

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

You may assume all the characters consist of printable ascii characters.

Example 1:

Input: ["h","e","l","l","o"]
Output: ["o","l","l","e","h"]

Example 2:

Input: ["H","a","n","n","a","h"]
Output: ["h","a","n","n","a","H"]

The accepted solution is


class Solution:
    def reverseString(self, s):
        """
        :type s: str
        :rtype: str
        """
        #base case
        if len(s) <= 1:
            return s
        #recur case 
        elif len(s) >= 2:
            n=len(s)
            return self.reverseString(s[n//2:])+self.reverseString(s[:n//2])

Two Problem with the solution:

1, Not modify in-place

2, It's expensive to recursively slicing a string.

As the first step to improve it, introduced parameters lo and hi to store index


class Solution:
    def reverseString(self, s, lo=0, hi=None):
        """
        :type s: str
        :rtype: None
        """
        if hi == None:
            hi = len(s)
      #base case
        if hi <= 1:
            return s

        #recur case 
        elif hi >= 2:
            mid = hi // 2
            left = self.reverseString(s, lo, mid)
            right = self.reverseString(s, mid, hi)
            return left + right               

It report error

 RecursionError: maximum recursion depth exceeded in comparison


Ran 1 test in 0.005s

What' s the problem?

5 个答案:

答案 0 :(得分:2)

To do this without space, you need to swap. You can't add array slices. Instead of splitting the indexes in the middle, which will never let you swap opposite pairs (expect in the base case).

You can see it, if you imagine the recursion visually. You start with a list like:

1, 2, 3, 4
^        ^ <-- these need to swap in a reverse

But after your first recursive call you split this into:

---- | ----
1, 2   3, 4
^         ^  <-- these still need to be swapped, bu when?

Now branch one has no way to get at the 4 in branch two to swap unless there's a non-obvious way to do it as the recursion unwinds.

You can instead (much more easily) walk you indexes in from both ends and swap as you go. Then your base case is just when they meet in the middle:

class Solution:
    def reverseString(self, s, lo=0, hi=None):
        if hi == None:
            hi = len(s) - 1

        if hi <= lo:
            return s

        s[lo], s[hi] = s[hi], s[lo]
        return self.reverseString(s, lo + 1, hi - 1)


s = Solution()
s.reverseString([1, 2, 3, 4])
# [4, 3, 2, 1]
s.reverseString([1, 2, 3, 4, 5])
#[5, 4, 3, 2, 1]

答案 1 :(得分:1)

I am not sure why are you doing recursion. You can simply take two pointers, one at the start and one at the end of the string, start by swapping those characters, and move the pointers towards each other, until they cross, and then you break and return the reversed string.

class Solution:
    def reverseString(self, s):

        if len(s) <= 1: return s
        # The two pointers
        lo = 0
        hi = len(s) - 1
        # Iterate till both pointers cross
        while lo < hi:
            # swap the characters
            tmp = s[lo]
            s[lo] = s[hi]
            s[hi] = tmp
            # increment the pointers
            lo += 1
            hi -= 1
        return s


s = Solution()
print(s.reverseString(['h']))
print(s.reverseString(["h","e","l","l","o"]))
print(s.reverseString(["h","e","l","l","o","w","o","r","l","d"]))
#['h']
#['o', 'l', 'l', 'e', 'h']
#['d', 'l', 'r', 'o', 'w', 'o', 'l', 'l', 'e', 'h']

In addition, the recursive approach for the same is as follows

class Solution:
    def reverseString(self, s, lo=0, hi=None):

        #If one character or less in the string, return the string
        if len(s) <= 1:
            return s

        #The last index should be placed at the end of the string
        if hi == None:
            hi = len(s) - 1

        #If the two indexes cross, return the string
        if hi < lo:
            return s

        #swap the low and high characters
        tmp = s[lo]
        s[lo] = s[hi]
        s[hi] = tmp
        #Recursively call the function
        return self.reverseString(s, lo + 1, hi - 1)

s = Solution()
print(s.reverseString(['h']))
print(s.reverseString(["h","e","l","l","o"]))
print(s.reverseString(["h","e","l","l","o","w","o","r","l","d"]))
#['h']
#['o', 'l', 'l', 'e', 'h']
['d', 'l', 'r', 'o', 'w', 'o', 'l', 'l', 'e', 'h']

答案 2 :(得分:0)

这里是针对此问题的解决方案:

class Solution(object):
    def reverseString(self, s, left=0, right=0):
        if right == 0:
            right = len(s) - 1

        if left >= right:
            return

        temp = s[right]
        s[right] = s[left]
        s[left] = temp
        self.reverseString(s, left+1, right -1)

答案 3 :(得分:0)

public class ReverseString {
    public void reverseString(char[] s){
        if(s.length<=1) {
            return;
        }
        int j=0;
        int i=s.length-1;
        while(i>j){
            char tmp;
            tmp=s[j];
            s[j]=s[i];
            s[i]=tmp;
            j++;
            i--;
        }
    }
}

答案 4 :(得分:0)

这是一个就地递归算法。就地基本上意味着不使用任何辅助数据结构。请记住,我们总是在内部使用堆栈来执行递归。 基本情况:如果 left >= right,则什么都不做。 否则:交换 s[left] 和 s[right] 并调用 helper(left + 1, right - 1)。

为了解决这个问题,调用 helper 函数,将头尾索引作为参数传递:return helper(0, len(s) - 1).

def reverseString(s):
    def helper(left, right):
        if left < right:
            s[left], s[right] = s[right], s[left]
            helper(left + 1, right - 1)
    helper(0, len(s) - 1)

时间复杂度 - O(n)

辅助空间 - O(n)