一、Problem
给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对应有 node.val 枚硬币,并且总共有 N 枚硬币。
在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。(移动可以是从父结点到子结点,或者从子结点移动到父结点。)。
返回使每个结点上只有一枚硬币所需的移动次数。
输入:[3,0,0]
输出:2
解释:从树的根结点开始,我们将一枚硬币移到它的左子结点上,一枚硬币移到它的右子结点上。
输入:[0,3,0]
输出:3
解释:从根结点的左子结点开始,我们将两枚硬币移到根结点上 [移动两次]。然后,我们把一枚硬币从根结点移到右子结点上。
提示:
1<= N <= 100
0 <= node.val <= N
二、Solution
方法一:后序遍历
因为我们要得到子节点的信息,所以后序遍历最佳;又因为最终的形状是每个结点都只有 颗金币,那假设某一个叶子结点 node 的金币数为 ,则结点分配一颗金币所需要的步骤数为(x-1), 的结果无外乎几种:
- :表示该结点不需要分配金币(已经有 1 颗金币)
- :表示该结点没有金币,需要被分配
- :表示该结点的金币数大于 ,此时也要将多余的 颗硬币移动
回到该叶子结点 node 的父亲 fa,如果叶子结点需要的硬币数为 1,如果父亲 fa 也没有硬币,那么该父亲 fa 向上传递的信息将会是 -2;但如果 fa 的右子节点有 2 个硬币多余,那么 fa 向上传递的信息将会是 0
class Solution {
public:
int op;
int dfs(TreeNode* root) {
if (root == NULL)
return 0;
int l = dfs(root->left), r = dfs(root->right), cur = l+r+root->val;
op += abs(cur-1);
return cur-1;
}
int distributeCoins(TreeNode* root) {
dfs(root);
return op;
}
};
复杂度分析
- 时间复杂度:,
- 空间复杂度:,