作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/distribute-coins-in-binary-tree/

题目描述

Given the root of a binary tree with N nodes, each node in the tree has node.val coins, and there are N coins total.

In one move, we may choose two adjacent nodes and move one coin from one node to another. (The move may be from parent to child, or from child to parent.)

Return the number of moves required to make every node have exactly one coin.

Example 1:

Input: [3,0,0]
Output: 2
Explanation: From the root of the tree, we move one coin to its left child, and one coin to its right child.

Example 2:

Input: [0,3,0]
Output: 3
Explanation: From the left child of the root, we move two coins to the root [taking two moves]. Then, we move one coin from the root of the tree to the right child.

Example 3:

Input: [1,0,2]
Output: 2

Example 4:

Input: [1,0,0,null,3]
Output: 4

Note:

  1. 1<= N <= 100
  2. 0 <= node.val <= N

题目大意

题目给出了一个二叉树,每个节点都有个数字代表当前节点有多少个金币,保证所有节点的金币数量之和等于节点个数。现在要求把金币平分到每个节点,使得每个节点都只放1个金币。问需要的移动次数是多少?

解题方法

递归

看到二叉树的题目我们一般想到递归,这个题也是如此。这个题是个难的的好题,确实很新颖。

首先,给定了一个二叉树的状态,只要不做重复移动,那么可以证明,移动是无状态的。也就是说,最终的移动次数不会因为先给谁后给谁,或者先移动几个再移动几个,再或者把某些金币移动到近的节点把另外一些金币移动到远的节点而有所不同。总之,我们可以放心大胆地,把金币移动到位,而不需要考虑把具体地金币移动到哪个确切的位置。

所以,我的思路就是分别统计左右子树缺少的金币个数,然后把每个节点和其子树总体的金币分配到位。累计所有节点和其子树所需要的移动次数就是结果。

每个子树缺少的金币数,等于节点数 - 金币数。因为题目确保了所有金币的和等于所有节点数,所以左子树缺少的金币数+该节点缺少的金币数+右子树缺少的金币数=0.我们每次把每个节点和其子树搞平衡,即左子树、该节点、右子树的节点数都等于金币数。注意此时,虽然左右子树总的不缺金币,但是内部仍然分配不均。所以,记录把这个节点搞平衡需要移动的金币数,然后累加上左子树和右子树搞平衡需要移动的金币数即为所求。

下面考虑,如果知道了左右子树需要的金币数,将他们搞平衡需要多少移动步数?答案是左右子树需要的金币数的绝对种子和。这个怎么理解?其实就是需要把子树多的金币挪给根节点,然后再从根节点分配给另一个缺少金币的子树对应的金币。举个栗子:

对于上面的树,左子树缺少-2个金币,右子树缺少1个金币。所以先把左子树多的那两个金币移动到根节点,然后根节点再给右子树分配缺的1个金币即可。因此总的移动次数是左右子树缺少的金币的和。

具体到代码,我们需要一个统计某个子树需要多少金币的函数need();需要计算把自身,左右子树都平衡,需要移动的coins个数的函数helper()。

因为代码比较简单,已经有注释,我就不讲代码了。

c++代码如下:

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int distributeCoins(TreeNode* root) {
int res = 0;
helper(root, res);
return res;
}
// 统计把自身,左右子树都平衡,需要移动的coins个数
void helper(TreeNode* root, int& res) {
if (!root) return;
// 左、右子树缺多少
int left = need(root->left);
int right = need(root->right);
//左,右子树和自身都平衡需要的移动数
res += abs(left) + abs(right);
helper(root->left, res);
helper(root->right, res);
}
// 为了使该子树均匀,需要的coins数
// 节点数 - coins
int need(TreeNode* root) {
if (!root) return 0;
if (count_.count(root))
return count_[root];
int res = need(root->left) + 1 - root->val + need(root->right);
count_[root] = res;
return res;
}
private:
unordered_map<TreeNode*, int> count_;
};

日期

2019 年 1 月 20 日 —— 这次周赛有点简单

【LeetCode】979. Distribute Coins in Binary Tree 解题报告(C++)的更多相关文章

  1. LeetCode 979. Distribute Coins in Binary Tree

    原题链接在这里:https://leetcode.com/problems/distribute-coins-in-binary-tree/ 题目: Given the root of a binar ...

  2. LC 979. Distribute Coins in Binary Tree

    Given the root of a binary tree with N nodes, each node in the tree has node.val coins, and there ar ...

  3. 【leetcode】979. Distribute Coins in Binary Tree

    题目如下: Given the root of a binary tree with N nodes, each node in the tree has node.val coins, and th ...

  4. 【LeetCode】993. Cousins in Binary Tree 解题报告(C++ & python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS BFS 日期 题目地址:https://le ...

  5. 【LeetCode】543. Diameter of Binary Tree 解题报告 (C++&Java&Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcode ...

  6. LeetCode 606 Construct String from Binary Tree 解题报告

    题目要求 You need to construct a string consists of parenthesis and integers from a binary tree with the ...

  7. LeetCode 104 Maximum Depth of Binary Tree 解题报告

    题目要求 Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the ...

  8. 【LeetCode】863. All Nodes Distance K in Binary Tree 解题报告(Python)

    [LeetCode]863. All Nodes Distance K in Binary Tree 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...

  9. 【LeetCode】297. Serialize and Deserialize Binary Tree 解题报告(Python)

    [LeetCode]297. Serialize and Deserialize Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode ...

随机推荐

  1. 【R】爬虫案例

    爬取豆瓣相册 library(RCurl) library(XML) myHttpheader <- c("User-Agent"="Mozilla/5.0 (Wi ...

  2. 50. Plus One-Leetcode

    Plus One My Submissions QuestionEditorial Solution Total Accepted: 98403 Total Submissions: 292594 D ...

  3. SIG -MESH -1

    协议栈    node:成为蓝牙mesh网络中一员的设备被称为节点(Node). 蓝牙mesh规格定义了节点可能拥有的特性.具有这些特性中的一个或多个,即表示节点可以在网络中扮演相应的特殊角色.定义的 ...

  4. sed 修改文件

    总结 正确的修改进文件命令(替换文件内容):sed -i "s#machangwei#mcw#g" mcw.txt 正确的修改追加进文件命令(追加文件内容):sed -i &quo ...

  5. 双向链表——Java实现

    双向链表 链表是是一种重要的数据结构,有单链表和双向链表之分:本文我将重点阐述不带头结点的双向链表: 不带头结点的带链表 我将对双链表的增加和删除元素操作进行如下解析 1.增加元素(采用尾插法) (1 ...

  6. jenkins+Gitlab安装及初步使用

    安装包下载地址:https://packages.gitlab.com/gitlab/gitlab gitlab-cerpm 包国内下载地址: https://mirrors.tuna.tsinghu ...

  7. java通过JDBC访问数据库(最基本的查询)

    一.步骤介绍 1.通过Class.forName()加载驱动: 2.通过DriverManager.getConnection()获取Conncetion连接对象: 3.创建Statement对象传递 ...

  8. 通过静态分析和持续集成 保证代码的质量 (Helix QAC)1

    前言 现代软件开发团队面临着很多挑战,这些挑战包括:产品交付期限越来越紧,团队的分布越来越广,软件的复杂度越来越高,而且对软件的质量要求越来越高. 本文分为两个章节.第一章讨论持续集成的原理,持续集成 ...

  9. Mysql资料 慢查询

    目录 一.简介 二.查询 三.开启 永久配置 临时配置 四.测试 一.简介 MySQL的慢查询,全名是慢查询日志,是MySQL提供的一种日志记录,用来记录在MySQL中响应时间超过阀值的语句. 具体环 ...

  10. ES6解构赋值的简单使用

    相较于常规的赋值方式,解构赋值最主要的是'解构'两个字,在赋值的过程中要清晰的知道等号右边的结构. 先简单地看一下原来的赋值方式. var a=[1,2] 分析一下这句代码的几个点: (1)变量申明和 ...