Easy

题目描述

给你一个二叉树的根节点 root ,计算并返回 整个树 的坡度 。

一个树的 节点的坡度 定义即为,该节点左子树的节点之和和右子树节点之和的 差的绝对值 。如果没有左子树的话,左子树的节点之和为 0 ;没有右子树的话也是如此。

空结点的坡度是 0 。

整个树 的坡度就是其所有节点的坡度之和。

示例 1:

输入:root = [1,2,3]
输出:1
解释:
节点 2 的坡度:|0-0| = 0(没有子节点)
节点 3 的坡度:|0-0| = 0(没有子节点)
节点 1 的坡度:|2-3| = 1(左子树就是左子节点,所以和是 2 ;右子树就是右子节点,所以和是 3 )
坡度总和:0 + 0 + 1 = 1

示例 2:

输入:root = [4,2,9,3,5,null,7]
输出:15
解释:
节点 3 的坡度:|0-0| = 0(没有子节点)
节点 5 的坡度:|0-0| = 0(没有子节点)
节点 7 的坡度:|0-0| = 0(没有子节点)
节点 2 的坡度:|3-5| = 2(左子树就是左子节点,所以和是 3 ;右子树就是右子节点,所以和是 5 )
节点 9 的坡度:|0-7| = 7(没有左子树,所以和是 0 ;右子树正好是右子节点,所以和是 7 )
节点 4 的坡度:|(3+5+2)-(9+7)| = |10-16| = 6(左子树值为 3、5 和 2 ,和是 10 ;右子树值为 9 和 7 ,和是 16 )
坡度总和:0 + 0 + 0 + 2 + 7 + 6 = 15

示例 3:

输入:root = [21,7,14,1,1,2,2,3,3]
输出:9

提示:

  • 树中节点数目的范围在 [0, 10^4]
  • -1000 <= Node.val <= 1000

解题思路

这道题需要计算二叉树每个节点的坡度之和。关键在于理解坡度的定义:一个节点的坡度是其左子树所有节点值之和与右子树所有节点值之和的差的绝对值。

解题思路分为两个步骤:

  1. 对于每个节点,需要知道其左子树和右子树的节点值之和
  2. 计算该节点的坡度,并累加到总坡度中

最直观的思路是使用后序遍历(推荐解法)。我们可以设计一个递归函数,它返回以当前节点为根的子树所有节点值之和,同时在递归过程中计算每个节点的坡度。

具体实现:

  • 定义一个全局变量记录总坡度
  • 递归函数返回当前子树的节点值之和
  • 在递归过程中,利用左右子树返回的和来计算当前节点的坡度
  • 当前节点的坡度 = |左子树和 - 右子树和|
  • 当前子树和 = 左子树和 + 右子树和 + 当前节点值

这种方法只需要遍历树一次,每个节点被访问一次,非常高效。

代码实现

class Solution {
private:
    int totalTilt = 0;
    
    int calculateSum(TreeNode* node) {
        if (node == nullptr) {
            return 0;
        }
        
        int leftSum = calculateSum(node->left);
        int rightSum = calculateSum(node->right);
        
        totalTilt += abs(leftSum - rightSum);
        
        return leftSum + rightSum + node->val;
    }
    
public:
    int findTilt(TreeNode* root) {
        totalTilt = 0;
        calculateSum(root);
        return totalTilt;
    }
};
class Solution:
    def findTilt(self, root: Optional[TreeNode]) -> int:
        self.total_tilt = 0
        
        def calculate_sum(node):
            if not node:
                return 0
            
            left_sum = calculate_sum(node.left)
            right_sum = calculate_sum(node.right)
            
            self.total_tilt += abs(left_sum - right_sum)
            
            return left_sum + right_sum + node.val
        
        calculate_sum(root)
        return self.total_tilt
public class Solution {
    private int totalTilt = 0;
    
    private int CalculateSum(TreeNode node) {
        if (node == null) {
            return 0;
        }
        
        int leftSum = CalculateSum(node.left);
        int rightSum = CalculateSum(node.right);
        
        totalTilt += Math.Abs(leftSum - rightSum);
        
        return leftSum + rightSum + node.val;
    }
    
    public int FindTilt(TreeNode root) {
        totalTilt = 0;
        CalculateSum(root);
        return totalTilt;
    }
}
var findTilt = function(root) {
    let totalTilt = 0;
    
    function getSum(node) {
        if (!node) return 0;
        
        let leftSum = getSum(node.left);
        let rightSum = getSum(node.right);
        
        totalTilt += Math.abs(leftSum - rightSum);
        
        return node.val + leftSum + rightSum;
    }
    
    getSum(root);
    return totalTilt;
};

复杂度分析

复杂度类型分析
时间复杂度O(n),其中 n 是树中节点的数量。每个节点被访问一次
空间复杂度O(h),其中 h 是树的高度。递归调用栈的深度等于树的高度,最坏情况下为 O(n)

相关题目