二叉树题目:在二叉树中分配硬币

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:在二叉树中分配硬币

出处:979. 在二叉树中分配硬币

难度

6 级

题目描述

要求

给定一个有 n \texttt{n} n 个结点的二叉树的根结点 root \texttt{root} root,树中的每个结点 node \texttt{node} node 上有 node.val \texttt{node.val} node.val 枚硬币。整个树中总共有 n \texttt{n} n 枚硬币。

在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点。可以从父结点移动到子结点,或者从子结点移动到父结点。

返回使每个结点上恰好有一枚硬币所需的最少移动次数。

示例

示例 1:

二叉树题目:在二叉树中分配硬币_第1张图片

输入: root   =   [3,0,0] \texttt{root = [3,0,0]} root = [3,0,0]
输出: 2 \texttt{2} 2
解释:从树的根结点开始,我们将一枚硬币移到它的左子结点上,一枚硬币移到它的右子结点上。

示例 2:

二叉树题目:在二叉树中分配硬币_第2张图片

输入: root   =   [0,3,0] \texttt{root = [0,3,0]} root = [0,3,0]
输出: 3 \texttt{3} 3
解释:从根结点的左子结点开始,我们将两枚硬币移到根结点上(移动两次)。然后,我们把一枚硬币从根结点移到右子结点上。

数据范围

  • 树中结点数目是 n \texttt{n} n
  • 1 ≤ n ≤ 100 \texttt{1} \le \texttt{n} \le \texttt{100} 1n100
  • 0 ≤ Node.val ≤ n \texttt{0} \le \texttt{Node.val} \le \texttt{n} 0Node.valn
  • 所有的 Node.val \texttt{Node.val} Node.val 之和是 n \texttt{n} n

解法

思路和算法

为了计算平均分配硬币的最少移动次数,需要计算每个子树中的硬币数与结点数的差值。差值等于 0 0 0 表示子树中的硬币树等于结点数;差值大于 0 0 0 表示子树中的硬币数大于结点数,需要将多余的硬币移动到当前子树根结点的父结点;差值小于 0 0 0 表示子树中的硬币数小于结点数,需要将缺少的硬币从当前子树根结点的父结点移动到当前子树。在计算每个子树中的硬币数与结点数的差值时,同步计算移动次数。

如果二叉树为空,则差值为 0 0 0。如果二叉树不为空,则差值为的左子树的差值、右子树的差值与根结点的差值之和,其中左子树的差值与右子树的差值是规模更小的问题,可以使用同样的方法计算,根结点的差值等于根结点值减 1 1 1,即根结点的硬币数与目标硬币数(目标硬币数为 1 1 1)之差。得到左子树的差值与右子树的差值之后即可更新移动次数。对于每个子树,如果差值为 x x x,则当 x > 0 x > 0 x>0 时需要将 ∣ x ∣ |x| x 个硬币从该子树移动到根结点,当 x < 0 x < 0 x<0 时需要将 ∣ x ∣ |x| x 个硬币从根结点移动到该子树,因此需要 ∣ x ∣ |x| x 次移动。

计算二叉树的差值可以使用深度优先搜索实现。整个过程是一个递归的过程,递归的终止条件是当前子树为空,此时差值为 0 0 0。其余情况下,首先计算左子树和右子树的差值,然后计算当前子树的差值并更新移动次数。

遍历结束之后即可得到平均分配硬币的最少移动次数。由于上述计算过程中,移动次数等于需要移动的硬币数,因此可以确保得到的移动次数是最少的。

代码

class Solution {
    int moves = 0;

    public int distributeCoins(TreeNode root) {
        count(root);
        return moves;
    }

    public int count(TreeNode node) {
        if (node == null) {
            return 0;
        }
        int countLeft = count(node.left);
        int countRight = count(node.right);
        moves += Math.abs(countLeft) + Math.abs(countRight);
        return countLeft + countRight + node.val - 1;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点都被访问一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉树的高度,最坏情况下是 O ( n ) O(n) O(n)

你可能感兴趣的:(数据结构和算法,#,树,树,二叉树)