leetcode
leetcode 2251 ~ 2300
二叉树的堂兄弟节点 II

二叉树的堂兄弟节点 II

难度:

标签:

题目描述

Given the root of a binary tree, replace the value of each node in the tree with the sum of all its cousins' values.

Two nodes of a binary tree are cousins if they have the same depth with different parents.

Return the root of the modified tree.

Note that the depth of a node is the number of edges in the path from the root node to it.

 

Example 1:

Input: root = [5,4,9,1,10,null,7]
Output: [0,0,0,7,7,null,11]
Explanation: The diagram above shows the initial binary tree and the binary tree after changing the value of each node.
- Node with value 5 does not have any cousins so its sum is 0.
- Node with value 4 does not have any cousins so its sum is 0.
- Node with value 9 does not have any cousins so its sum is 0.
- Node with value 1 has a cousin with value 7 so its sum is 7.
- Node with value 10 has a cousin with value 7 so its sum is 7.
- Node with value 7 has cousins with values 1 and 10 so its sum is 11.

Example 2:

Input: root = [3,1,2]
Output: [0,0,0]
Explanation: The diagram above shows the initial binary tree and the binary tree after changing the value of each node.
- Node with value 3 does not have any cousins so its sum is 0.
- Node with value 1 does not have any cousins so its sum is 0.
- Node with value 2 does not have any cousins so its sum is 0.

 

Constraints:

  • The number of nodes in the tree is in the range [1, 105].
  • 1 <= Node.val <= 104

代码结果

运行时间: 319 ms, 内存: 54.9 MB


/*
 * 题目思路:
 * 1. 使用Java Stream API实现堂兄弟节点值和的计算。
 * 2. 遍历每层节点,使用Map存储每层的节点信息。
 * 3. 对于每个节点,计算堂兄弟节点的和,更新节点的值。
 */
import java.util.*;
import java.util.stream.Collectors;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    public TreeNode replaceCousinSum(TreeNode root) {
        if (root == null) return null;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            List<TreeNode> nodes = new ArrayList<>();
            for (int i = 0; i < levelSize; i++) {
                TreeNode node = queue.poll();
                nodes.add(node);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
            int levelSum = nodes.stream().mapToInt(n -> n.val).sum();
            nodes.forEach(node -> {
                int siblingSum = (node.left != null ? node.left.val : 0) + (node.right != null ? node.right.val : 0);
                node.val = levelSum - siblingSum;
            });
        }
        return root;
    }
}

解释

方法:

该题解采用了深度优先搜索算法(DFS)来解决问题。分为两个主要步骤: 1. 首先,通过第一个DFS(函数dfs1)遍历整棵树并计算出每一层所有节点值的总和,这些总和保存在dSum列表中。每个索引i对应的dSum[i]表示第i层所有节点的值的总和。 2. 第二个DFS(函数dfs2)用于更新每个节点的值。在这个阶段,对于每个节点,我们计算其所有堂兄弟节点值的总和。这通过从当前层总和中减去该节点直接子节点的值来实现。这种计算保证了节点值被替换为所有堂兄弟的值的和。 整个过程确保了每个节点都被正确地替换为其堂兄弟节点的值之和,满足题目要求。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在第一个DFS函数中,你是如何确保`dSum`列表准确地记录了每一层节点的总和?特别是当存在不平衡树时。
在第一个DFS函数`dfs1`中,使用了递归的方式来遍历整棵树。函数接收当前节点以及节点的深度`depth`作为参数。每次访问一个新的深度层次时,首先检查`dSum`列表的长度是否等于当前的深度。如果等于,意味着这是该深度层次第一次被访问,因此在`dSum`列表中添加一个新的元素(初始值为0)。之后,无论树的形态如何(是否平衡),都能够保证每个节点的值都加到对应深度的总和中。这种方法通过递归确保了从根节点到每一个叶子节点的路径都被遍历,且每个节点根据其深度正确地贡献了值到`dSum`中。
🦆
在第二个DFS函数中,为什么直接从`dSum[depth]`中减去当前节点的子节点值来更新其值?这样做是否能确保当前节点的值正确地反映了所有堂兄弟节点的总和?
在第二个DFS函数`dfs2`中,目的是将每个节点的值更新为所有堂兄弟节点值的总和。`dSum[depth]`在第一个DFS中已经计算了包含当前节点所有同级节点(包括其自身和所有堂兄弟节点)的值总和。为了得到仅堂兄弟节点的总和,需要从`dSum[depth]`中减去当前节点的直接子节点的值(因为子节点属于下一层,其值不应包括在当前层节点的计算中)。这样确保了更新的值是除去自身所有子节点的值后,该层其他节点的总和,即堂兄弟节点的总和。这种方法正确地实现了题目要求的功能,即每个节点值反映了所有堂兄弟节点的总和。
🦆
在处理节点值替换时,根节点的值为什么被设置为0?这是否意味着根节点没有堂兄弟节点?
在题目中,堂兄弟节点定义为在同一深度但父节点不同的节点。根节点位于深度0,且在正常的二叉树中,根节点是唯一的,没有其他节点与其在同一深度上,因此它没有堂兄弟节点。因此,在`dfs2`函数开始时将根节点的值设置为0是合理的,因为按题目要求,它应该被其堂兄弟节点的总和替换,而它没有堂兄弟,所以和为0。这种设计准确地反映了题目的逻辑与要求。

相关问题