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?
答案 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)