目录链接:
力扣编程题-解法汇总_分享+记录-CSDN博客
GitHub同步刷题项目:
https://github.com/September26/java-algorithms
原题链接:. - 力扣(LeetCode)
描述:
给你一个整数 n
表示一棵 满二叉树 里面节点的数目,节点编号从 1
到 n
。根节点编号为 1
,树中每个非叶子节点 i
都有两个孩子,分别是左孩子 2 * i
和右孩子 2 * i + 1
。
树中每个节点都有一个值,用下标从 0 开始、长度为 n
的整数数组 cost
表示,其中 cost[i]
是第 i + 1
个节点的值。每次操作,你可以将树中 任意 节点的值 增加 1
。你可以执行操作 任意 次。
你的目标是让根到每一个 叶子结点 的路径值相等。请你返回 最少 需要执行增加操作多少次。
注意:
- 满二叉树 指的是一棵树,它满足树中除了叶子节点外每个节点都恰好有 2 个子节点,且所有叶子节点距离根节点距离相同。
- 路径值 指的是路径上所有节点的值之和。
示例 1:
输入:n = 7, cost = [1,5,2,2,3,3,1] 输出:6 解释:我们执行以下的增加操作: - 将节点 4 的值增加一次。 - 将节点 3 的值增加三次。 - 将节点 7 的值增加两次。 从根到叶子的每一条路径值都为 9 。 总共增加次数为 1 + 3 + 2 = 6 。 这是最小的答案。
示例 2:
输入:n = 3, cost = [5,3,3] 输出:0 解释:两条路径已经有相等的路径值,所以不需要执行任何增加操作。
提示:
3 <= n <= 105
n + 1
是2
的幂cost.length == n
1 <= cost[i] <= 104
解题思路:
这道题其实是一道递归遍历的题目,只不过应该从叶子节点向上遍历,而不是从根节点向下遍历。
首先,我们分别使用level记录其有多少层,使用abs记录添加多少次。
其次某个节点找到其父节点,只要把相邻两个节点靠前的那个节点i除以2即可得到其父节点位置。
最后,我们可以构建这样的循环,首先遍历最后一层级节点,保证相邻的两个节点值相等,不相等则填平,然后把填平后的值加到其父节点上,构建父节点的权限。
比如题目中的[1,5,2,2,3,3,1]中,最后一层的节点位置是[2^2-1,2^3-1]的范围,比较3,4位置用较大值减去较小值,差值添加到abs中。然后把较大值加到父节点上,比如3,4位置的父节点就是3/2=1。
接下来倒数第二层也是一样的逻辑,直到第二层。
看了官方题解之后,发现其实也没必要按照层级去逆序遍历,只要从后向前遍历其实也一样的,官方题解会更简单。
代码:
class Solution {
public:
int minIncrements(int n, vector<int> &cost)
{
int level = 0;
n++;
while (n > 1)
{
n = n / 2;
level++;
}
int abs = 0;
while (level > 1)
{
for (int i = pow(2, level - 1) - 1; i < pow(2, level) - 1; i = i + 2)
{
int maxNum = max(cost[i], cost[i + 1]);
int minNum = min(cost[i], cost[i + 1]);
abs += (maxNum - minNum);
cost[i / 2] += maxNum;
}
level--;
}
return abs;
}
};