难度: Medium
Submission
运行时间: 324 ms
内存: 22.6 MB
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def maxValue(self, root: TreeNode, k: int) -> int: def maxSubTree(node): if not node: return [0] l = maxSubTree(node.left) r = maxSubTree(node.right) res = [0] * (k + 1) res[0] = l[-1] + r[-1] for i in range(len(l)): for j in range(min(len(r), k - i)): res[i + j + 1] = max(res[i + j], res[i + j + 1], l[i] + r[j] + node.val) return res[: len(l) + len(r)] return max(maxSubTree(root))
Explain
该题解采用递归方法进行动态规划。首先定义一个辅助函数 maxSubTree,该函数返回一个列表,其中包含以当前节点为根的子树内,各个可能的蓝色节点群组的最大值累计。列表中的每个位置i表示恰好有i个连续节点被染色的情况下,可以获得的最大价值。函数首先处理基本情况,如果当前节点为空,则返回一个只包含0的列表。然后,它递归地计算左右子树的最大价值列表。使用两层循环遍历左右子树返回的列表,来确定在当前节点下,形成不同大小的蓝色节点群组的最大价值。外层循环和内层循环分别遍历左子树和右子树返回的列表,通过将左右子树的某些价值组合并加上当前节点的价值,来更新结果列表。最后,返回整棵树调用 maxSubTree 后的最大价值。
时间复杂度: O(n*k^2)
空间复杂度: O(n*k)
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def maxValue(self, root: TreeNode, k: int) -> int: def maxSubTree(node): # 如果节点为空,返回包含一个0的列表 if not node: return [0] # 递归计算左右子树的最大价值列表 l = maxSubTree(node.left) r = maxSubTree(node.right) # 初始化当前节点的最大价值列表 res = [0] * (k + 1) res[0] = l[-1] + r[-1] # 更新当前节点下各种可能的连续蓝色节点群组的最大价值 for i in range(len(l)): for j in range(min(len(r), k - i)): res[i + j + 1] = max(res[i + j], res[i + j + 1], l[i] + r[j] + node.val) return res[: len(l) + len(r)] # 返回整棵树的最大价值 return max(maxSubTree(root))
Explore
在递归函数`maxSubTree`中,当节点为null时返回包含一个0的列表,这里的0代表的是,在没有任何节点的情况下,染色节点个数为0时的最大价值。因为没有节点可染色,所以最大价值是0。这个返回值为递归处理提供了一个基准情况,确保当递归到空节点时,可以正常地继续计算而不会出现错误或异常。
在计算`res[0]`时使用`l[-1] + r[-1]`,这个操作代表的是计算当前节点不被染色时,其左右子树能够达到的最大价值的和。这里选择列表的最后一个元素进行相加是因为,列表的最后一个元素(即`l[k]`和`r[k]`)代表了在子树中恰好有k个连续节点被染成蓝色时的最大价值。因此,当当前节点不染色时,我们希望利用左右子树分别达到其最大染色潜力的和,这就是`l[-1]`和`r[-1]`的含义。
在更新`res`数组时,内层循环的终止条件设置为`k - i`是为了确保总的染色节点数不超过k。这里`i`表示从左子树中选取的染色节点数,而`j`表示从右子树中选取的染色节点数。因此,`i + j + 1`(加1表示当前节点也被染色)是当前节点下形成的蓝色节点群组的总数,这个值必须小于等于k。通过设置循环的终止条件为`k - i`,我们确保了在任何时候,左子树和右子树中选取的节点数之和不会超过k减去已选择的左子树节点数,从而保证整个节点群组的大小符合要求。