【问题标题】:A in-place recursive solution to reverse a string反转字符串的就地递归解决方案
【发布时间】:2019-04-16 23:36:06
【问题描述】:

我正在学习 leetcode 的特色教程 Recursion I 中的递归基础知识

第一个练习是反转一个字符串Reverse String - LeetCode

编写一个反转字符串的函数。输入字符串以字符数组的形式给出char[]

不要为另一个数组分配额外空间,您必须通过使用 O(1) 额外内存就地修改输入数组来做到这一点。

你可以假设所有字符都由printable ascii characters组成。

示例 1:

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

示例 2:

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

接受的解决方案是


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

解决方案的两个问题:

1、不就地修改

2、递归地对字符串进行切片很昂贵。

作为改进的第一步,引入参数lohi来存储索引


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               

报错

 RecursionError: 比较超过最大递归深度


在 0.005 秒内运行 1 次测试

有什么问题?

【问题讨论】:

  • 我认为这是你的权利 = self.reverseString(s, mid, hi)。我不明白为什么这个分支会达到基本情况,因为 hi 永远不会改变。
  • 根本问题是你没有测试你的代码。您对基本情况的测试与处理hi 的逻辑不匹配。请参阅这个可爱的 debug 博客寻求帮助。
  • 将字符串转换为可变类型,然后将其反转并转换回来。一个列表的工作开销约为每个字符 50 个字节。
  • 为什么不像我下面那样迭代地做呢?
  • 这里的基本思想是有缺陷的。如果您想在没有空间的情况下执行此操作,则需要在某个时候交换元素。但是如果你在中间递归拆分列表,第一个和最后一个元素将永远不会在同一个树分支上。

标签: python algorithm


【解决方案1】:

要在没有空间的情况下执行此操作,您需要交换。您不能添加数组切片。而不是在中间拆分索引,这永远不会让您交换相反的对(在基本情况下除外)。

如果您直观地想象递归,您可以看到它。您可以从如下列表开始:

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

但是在你第一次递归调用之后,你把它分成:

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

现在,分支 1 无法在分支 2 中的 4 处进行交换,除非在递归展开时有一种不明显的方法可以做到这一点。

您可以改为(更容易)从两端引入索引并随时交换。那么你的基本情况就是他们在中间相遇时:

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]

【讨论】:

    【解决方案2】:

    我不确定你为什么要递归。您可以简单地获取两个指针,一个在字符串的开头,一个在字符串的结尾,首先交换这些字符,然后将指针彼此移动,直到它们交叉,然后您断开并返回反转的字符串。

    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']
    

    另外,同样的递归方法如下

    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']
    

    【讨论】:

    • 任务是在不使用额外空间的情况下递归地执行此操作。这些都不是。
    • 我没有使用额外的空间,我正在就地修改同一个列表?你能告诉我在哪里吗?
    • OP 声明 Do not allocate extra space for another array 我没有这样做
    • s[1:] 切片。 reverseString(s[1:]) + [s[0]] 是一个新数组。
    • 哦,明白了,我会改变它,但我没有在我的迭代方法中使用额外的空间!
    【解决方案3】:

    这里有解决这个问题的方法:

    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)
    

    【讨论】:

      【解决方案4】:
      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--;
              }
          }
      }
      

      【讨论】:

      • 嗨@wei chen,欢迎来到 StackOverflow!仅代码的答案通常不受欢迎,您可以在答案中添加解释吗?这将提高您的回答质量!
      【解决方案5】:

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

      为了解决这个问题,调用辅助函数,将头尾索引作为参数传递: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)

      【讨论】:

        【解决方案6】:

        这是我的解决方案。 二指针方法和二分查找

        s = ["h","e","l","l","o"]
        print(s)
        start = 0
        end = len(s)-1
        while start <= end:
            temp = s[start]
            s[start] = s[end]
            s[end] = temp
            start += 1
            end -= 1
        print((s))
        

        【讨论】:

        • 嗨@Abdul,欢迎来到StackOverFlow 社区?。您的回答似乎不错,但更多解释可以使它变得更好。
        • 当然我刚加入社区 :D
        【解决方案7】:

        这是我在 cpp 中的代码。我已经使用递归解决了这个问题,但不知道这是多少有效的解决方案?顺便说一句,下面的代码被接受。

        void recursive(int start, int end, vector<char>& s) {
            
            if(start >= s.size()/2) {
                
                return;
            }
            recursive(start+1, end-1, s);
            swap(s[start], s[end]);
        }
        
        
        void reverseString(vector<char>& s) {
            
            int size = s.size();
            recursive(0, size-1, s);
        }
        

        【讨论】:

        • 问题是关于 Python 的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-08-15
        • 1970-01-01
        • 2020-06-07
        • 2014-06-10
        • 1970-01-01
        • 2019-06-26
        相关资源
        最近更新 更多