递归专题总结 - 不断更新

递归套路解决链表问题:

1.找终止条件:当head指向链表只剩一个元素的时候,自然是不可能重复的,因此return
2.想想应该返回什么值:应该返回的自然是已经去重的链表的头节点
每一步要做什么:宏观上考虑,此时head.next已经指向一个去重的链表了,而根据第二步,我应该返回一个去重的链表的头节点。因此这一步应该做的是判断当前的head和head.next是否相等,如果相等则说明重了,返回head.next,否则返回head

例一:
我们以leetcode 24为例子,题目描述:两两交换链表,返回首结点

step1:找终止条件
(1)最后啥也不剩 (因为可能输入 []的情况,所以这种情况不能省略)
(2)最后只剩一个元素 直接返回
(3)最后剩两个元素 交换之后返回

step2:返回什么值
swap(s)表示返回两两交换后的链表的首指针

step3:

class Solution:
    def swapPairs(self, head: ListNode) -> ListNode:
        if head==None:
            return head
        elif head.next==None:
            return head
        elif head.next.next==None:
            tmp=head.next
            tmp.next=head
            head.next=None
            return tmp
        else:
            b=head.next
            head.next=self.swapPairs(b.next)
            b.next=head
            return b

在这里插入图片描述
例二:leetcode 110 平衡二叉树

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        
        #kernel:返回值的设置非常巧妙
        #若不是平衡树,返回-1
        #若是平衡树,返回max(left,right)+1 
        def depth(root):
            if root ==None:
                return 0
            if root:
                left=depth(root.left)
                if left==-1: 
                    return -1
                right=depth(root.right)
                if right==-1: 
                    return -1
                return  (max(left,right)+1) if abs(left-right)<2 else -1
        return False if depth(root)==-1 else True '

例三:二叉树的层次遍历 leetcode 102

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        #len(ans)表示当前队列的高度 正常情况在某一层遍历时 len(ans)=level+1
        #刚刚到某一层时 要在ans后新添一个[]
        def dfs(root,level):
            if root==None:
                return 
            if len(ans)==level:
                ans.append([])
            
            ans[level].append(root.val)
            if root.left:
                dfs(root.left,level+1)
            if root.right:
                dfs(root.right,level+1)
        ans=[]
        dfs(root,0)
        return ans
            

例四:“leetcode 337 打家劫舍”
递归+记忆化 可以大大缩减父子节点的重复计算
比如用Fibonacci计算 F(3) 其中F(2)会被重复计算
那么我们可以在递归的头部写上哈希表特判,如果在哈希表中,则无需计算
比如这道树形动态规划也可以用递归暴力解 加上记忆化 速度不会太慢

#一开始的思路是一层全部加起来 发现不行 只能用递归写
#首先写个最傻逼的递归 #然后递归加上记忆化
class Solution:
    def __init__(self):
        self.hashmap={}
    def rob(self, root: TreeNode) -> int:
        if root==None:
            return 0
        #记忆化 加速200倍
        if root in self.hashmap:
            return self.hashmap[root]
        if root:
            method1=root.val
            if root.left:
                method1+=self.rob(root.left.left)+self.rob(root.left.right)
            if root.right:
                method1+=self.rob(root.right.left)+self.rob(root.right.right)
            ans=max(method1,self.rob(root.left)+self.rob(root.right))
            self.hashmap[root]=ans
            return ans

另外一种解法
返回值是一个含两个元素的list
list[0]表示当前节点不偷,list[1]表示当前节点偷
注:max(list)返回list中最大元素

class Solution:
    def rob(self, root: TreeNode) -> int:
        return max(self.dp(root))
    #[0]表示不偷 [1]表示偷
    def dp(self,root):
        if root==None:
            return [0,0]
        left=self.dp(root.left)
        right=self.dp(root.right)
        return  [max(left)+max(right),root.val+left[0]+right[0]]

例五:复原IP地址 leetcode93

坑点:要补上 s[0]!=‘0’ 不然IP地址会出现前置0

class Solution:
    def __init__(self):
        self.ans=[]

    def restoreIpAddresses(self, s: str) -> List[str]:
        self.dfs(0,s,"")
        return self.ans
    #index表示目前加的位数
    def dfs(self,count,s,IP):
        if count==4:
            if s=='':
                self.ans.append(IP[1:])
            return 
        n=len(s)
        if n>0:
            self.dfs(count+1,s[1:],IP+'.'+s[0])
        if n>1 and s[0]!='0':
            self.dfs(count+1,s[2:],IP+'.'+s[0:2])
        if n>2:
            if int(s[0:3])<256 and s[0]!='0':
                self.dfs(count+1,s[3:],IP+'.'+s[0:3])

特别注意一个细节
我自己在记录全局回溯的答案时很喜欢返回 self.ans

注意要用 self.ans.append(tmp[:])
或者 self.ans.append(tmp.copy())
不能用引用传递 可变对象要拷贝出来

还有一个python list排序经常要用的易混点
L.sort() 原来的L改变 没有返回值
sorted(L) 原来L不变 返回一个排好序的副本
很好理解和记忆 L.sort()调用类里面的方法 所以会改变这个对象 没有返回值

回溯 去重操作

nums.sort()

if nums[i]==nums[i-1]: continue

若是限定了每个元素的使用次数
方法一:加入一个元素后 下一次递归传入参数要减去元素

self.dfs(nums[:i]+nums[i+1:], tmpList)

方法二

if i>preIndex and candidates[i]==candidates[i-1]: continue

发布了16 篇原创文章 · 获赞 3 · 访问量 1070

猜你喜欢

转载自blog.csdn.net/weixin_39666736/article/details/104061813