📅  最后修改于: 2023-12-03 15:42:13.243000             🧑  作者: Mango
该题目是 GATE CS Mock 2018 的一道题目,旨在测试程序员对二叉树遍历、递归和动态规划的掌握程度。
给定一个二叉树,每个节点有一个权重值和一个颜色值。定义一个节点的权重为该节点本身的权重值和所有左子节点权重值和右子节点权重值的和。现在需要将该二叉树的所有节点的颜色值变成相同的值,使得所有节点的权重之和最小。请编写程序实现此过程。要求程序的时间复杂度不超过 O(N)。
输入格式为二叉树的层序遍历字符串,其中每个节点的格式为:
[val, color]
其中 val
代表节点的权重值,color
代表节点的颜色值(颜色值为一个整数)。
输出所有节点变色后的最小权重总和。
对于下面的二叉树:
3
/ \
2 1
/ \ / \
5 7 6 4
输入为:[[3,1], [2,2], [1,3], [5,4], [7,5], [6,4], [4,5]]
输出为:17
题目描述说明,所有节点可按某个颜色的方式染色。统计所有节点变色后的最小权重总和。
从题目中可以看到,要求变色后所有节点的权重之和最小,这提示我们需要考虑如何求出每个节点变色后的权重值。在这里我们可以使用递归的方法,对于每一个节点,我们先递归求出其左子树、右子树的权重和,再计算该节点的权重和。变色只需要将每个节点的颜色值修改为待变的颜色值即可。
递归求解的过程中,我们可以通过两个变量,一个表示当前节点变色后的权重和,一个表示当前节点为根的子树变色后的最小权重和来优化重复计算的问题。这种方法就是动态规划(Dynamic Programming)。
class TreeNode:
def __init__(self, val, color):
self.val = val
self.color = color
self.left = None
self.right = None
def modify_color(root, target_color):
def dfs(node, target_color):
if not node:
return 0, 0
# 如果已经计算过该节点变色后的权重和,直接返回
if (node, target_color) in memo:
return memo[(node, target_color)]
# 计算当前节点左右子树变色后的权重和及最小值
left_sum, left_min = dfs(node.left, target_color)
right_sum, right_min = dfs(node.right, target_color)
# 计算当前节点变色后的权重和及最小值
sum_val = node.val + left_sum + right_sum
min_val = sum_val + left_min + right_min
# 如果该节点为目标颜色,不需要再变色
if node.color == target_color:
memo[(node, target_color)] = (sum_val, min_val)
return sum_val, min_val
# 计算当前节点变色后的权重和及最小值
sum_val2 = node.val
min_val2 = min(left_sum + right_min, left_min + right_sum) + sum_val2
# 存储当前节点为目标颜色时的权重和及最小值
memo[(node, target_color)] = (sum_val, min(min_val, min_val2))
return sum_val, memo[(node, target_color)][1]
memo = {}
# 从根节点开始遍历
dfs(root, target_color)
# 返回根节点为目标颜色时的最小权重和
return memo[(root, target_color)][1]
在上述代码中,我们采用字典 memo 存储每个节点为目标颜色时的权重和及最小值。其中键是由当前节点和目标颜色组成的元组,值是另一个元组,第一个元素是当前节点变色后的权重和,第二个元素是当前节点为目标颜色时的最小权重和。
在代码中两个函数之间嵌套,这种方式是 Python 中一种常见的定义闭包的方法。