给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对应有 node.val 枚硬币,并且总共有 N 枚硬币。
在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。(移动可以是从父结点到子结点,或者从子结点移动到父结点。)。
返回使每个结点上只有一枚硬币所需的移动次数。
示例 1:
输入:[3,0,0] 输出:2 解释:从树的根结点开始,我们将一枚硬币移到它的左子结点上,一枚硬币移到它的右子结点上。
示例 2:
输入:[1,0,0,null,3] 输出:4
思路:题目中要求节点数为n,且金币总数也为n,最后要让所有节点的金币数都为1。按多往少给的想法,很难确定金币多的那个节点需要走多少次给到需要金币的节点。
因为获取金币的方式只要父子节点之间进行传递,若从反向思考问题(假设一开始是所有节点都有1个金币,要让节点持有金币情况变成题目给出的情况)
则可以知道一个节点需要给左孩子x个(可以是负数,负数理解孩子节点给父节点金币)金币,给右孩子y个金币,传递次数=abs(x)+abs(y),且此时该节点需要从父节点获得的金币个数为node->val+x+y-1(node本来就有1个金币,要给孩子x+y个金币,自己要有node->val个金币,多出来则)
从底往上推,叠加每个节点作为父节点时传递金币的次数。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int dfs(TreeNode* root,int& ret)
{
if(root==nullptr) return 0;
int left=0,right=0;
//判断需要给左、右孩子多少个金币
if(root->left) left=dfs(root->left,ret);
if(root->right) right=dfs(root->right,ret);
//结果为所有左、右绝对值依次相加
ret+=abs(left)+abs(right);
//返回此子树需要“接收”金币的次数
return root->val+left+right-1;
}
int distributeCoins(TreeNode* root) {
int ret=0;
dfs(root,ret);
return ret;
}
};