Leetcode Day4 (动态规划II)(dp遇上二叉树)

  • python小知识
    • 看一下95, python中的树是怎么写的
  • 好题
    • 124

96 n个节点组成的不同二叉树个数

关键是递归:
如果现在我在n
那么n可以拆为:
以1为分割: 0 + n-1 (0个比1小, n-1个比1大)
以2为分割: 1 + n-2 (1个比2小, n-2个比2大)

以n为分割: n-1 + 0 (n-1个比n小, 0个比n大)
所以状态转移方程是:
G ( n ) = G ( 0 ) ∗ G ( n − 1 ) + G ( 1 ) ∗ ( n − 2 ) + . . . + G ( n − 1 ) ∗ G ( 0 ) G(n)=G(0)∗G(n−1)+G(1)∗(n−2)+...+G(n−1)∗G(0) G(n)=G(0)G(n1)+G(1)(n2)+...+G(n1)G(0)
这也称为卡特兰数

95 是96的升级, 不是返回个数而是所有的二叉树

class Solution:
    def generateTrees(self, n: int) -> List[TreeNode]:
        def generateTrees(start, end):
            if start > end:
                return [None,]
            
            allTrees = []
            for i in range(start, end + 1):  # 枚举可行根节点
                # 获得所有可行的左子树集合
                leftTrees = generateTrees(start, i - 1)
                
                # 获得所有可行的右子树集合
                rightTrees = generateTrees(i + 1, end)
                
                # 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
                for l in leftTrees:
                    for r in rightTrees:
                        currTree = TreeNode(i)
                        currTree.left = l
                        currTree.right = r
                        allTrees.append(currTree)
            
            return allTrees
        
        return generateTrees(1, n) if n else []

一个关键的问题, 为什么start > end时返回的是[None]
在这里插入图片描述

124 可以从任何地方开始的路径之和最大

这道题虽然是二叉树, 但可以从二叉树的任意一个地方开始, 就把问题变得很难了
我的第一想法是: 按照他的思路就输了(不能够这样想: 从任意一个节点出发), 原因是题所给的数据结构不支持node.parent, 往上遍历是非常困难的. 我们仍然应该保持从上到下遍历的习惯.

此时我已经有一点初步idea:

class Solution:
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        self.ans = -float('inf')
        def score(node):
            if node == None:
                return 0
            else:
                l = score(node.left)
                r = score(node.right)
                L = l + node.val
                R = r + node.val
                A = l + r + node.val
                best = max(L, R, A)
                self.ans = max(self.ans, best)
                return best
        score(root)
        return self.ans

但是这个方法在[2, -1, -2]的情况下不对, 原来对于node, 我们不仅可以左, 右, 左加右, 还能只保留自己
改为best = max(L, R, A, node.val)后结果还有一些case过不了
结果错误在于:

你原来的代码主要问题是在返回值时包含了 A(跨越左右子树的路径),这可能导致在更高层的节点计算时使用了一个已经"拐弯"的路径,违反了路径的定义(路径被定义为从树中任意节点出发,达到任意节点的序列,且路径每到达一个节点,只能选择向上或者向下访问一个相邻节点,不能重复访问)。

应该是

class Solution:
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        self.ans = float('-inf')
        def score(node):
            if node == None:
                return 0
            else:
                l = score(node.left)
                r = score(node.right)
                L = l + node.val
                R = r + node.val
                A = l + r + node.val
                self.ans = max(self.ans, L, R, A, node.val)
                return max(L, R, node.val)  # 只返回单边最大路径
        score(root)
        return self.ans

337 二叉树中的打家劫舍

第一次直接写出

class Solution:
   def rob(self, root: Optional[TreeNode]) -> int:
       def money(node, steal):
           if node == None:
               return 0
           if steal:
               return node.val + money(node.left, False) + money(node.right, False)
           else:
               l_steal = money(node.left, True)
               l_not_steal = money(node.left, False)
               r_steal = money(node.right, True)
               r_not_steal = money(node.right,False)
               return max(l_not_steal, l_steal) + max(r_not_steal, r_steal)
       return max(money(root,False), money(root, True))

但很不幸的是最后两个cases超时了
用memoization来优化一下:

class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        memo = {}
        
        def money(node):
            if node is None:
                return (0, 0)
            if node in memo:
                return memo[node]
            
            left = money(node.left)
            right = money(node.right)
            
            # 如果当前节点被偷,则不能偷左右子节点
            rob = node.val + left[1] + right[1]
            # 如果当前节点不被偷,则可以选择偷或不偷左右子节点
            not_rob = max(left) + max(right)
            
            memo[node] = (rob, not_rob)
            return memo[node]
        
        return max(money(root))

打败了45%

class Solution:
    def rob(self, root: Optional[TreeNode]) -> int:
        def dfs(node):
            if not node:
                return 0, 0
            left = dfs(node.left)
            right = dfs(node.right)
            
            # 如果偷当前节点
            rob = node.val + left[1] + right[1]
            # 如果不偷当前节点
            not_rob = max(left) + max(right)
            
            return rob, not_rob
        return max(dfs(root))

这样更简单一点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值