leetcode
leetcode 1051 ~ 1100
祖父节点值为偶数的节点和

祖父节点值为偶数的节点和

难度:

标签:

题目描述

给你一棵二叉树,请你返回满足以下条件的所有节点的值之和:

  • 该节点的祖父节点的值为偶数。(一个节点的祖父节点是指该节点的父节点的父节点。)

如果不存在祖父节点值为偶数的节点,那么返回 0

 

示例:

输入:root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
输出:18
解释:图中红色节点的祖父节点的值为偶数,蓝色节点为这些红色节点的祖父节点。

 

提示:

  • 树中节点的数目在 1 到 10^4 之间。
  • 每个节点的值在 1 到 100 之间。

代码结果

运行时间: 56 ms, 内存: 18.6 MB


// Java solution using Java Streams for finding the sum of nodes with even-valued grandparent

/*
 * Approach:
 * 1. Flatten the tree nodes into a list using DFS.
 * 2. For each node, check if it has a grandparent and if the grandparent's value is even.
 * 3. Use Java Streams to filter nodes with even-valued grandparents and sum their values.
 */

import java.util.*;
import java.util.stream.*;

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

public class Solution {
    public int sumEvenGrandparent(TreeNode root) {
        List<TreeNode> nodeList = new ArrayList<>();
        dfs(root, null, null, nodeList);
        return nodeList.stream()
                .filter(node -> node[2] != null && node[2].val % 2 == 0)
                .mapToInt(node -> node[0].val)
                .sum();
    }

    private void dfs(TreeNode node, TreeNode parent, TreeNode grandparent, List<TreeNode[]> nodeList) {
        if (node == null) return;
        nodeList.add(new TreeNode[]{node, parent, grandparent});
        dfs(node.left, node, parent, nodeList);
        dfs(node.right, node, parent, nodeList);
    }
}

解释

方法:

这个解决方案使用深度优先搜索(DFS)来遍历整棵树,并在遍历过程中寻找符合条件的节点。首先检查当前节点值是否为偶数,如果是,那么它的孙子节点(如果存在)的值将被加到结果中。之后,递归地对左右子树应用同样的逻辑。这种方法确保了每个节点都被访问一次,且只有当节点的祖父节点的值为偶数时,节点的值才会被加入总和。

时间复杂度:

O(n)

空间复杂度:

O(n) in the worst case, O(log(n)) in the best case

代码细节讲解

🦆
在递归遍历树时,如果当前节点为奇数,是否还有必要检查其子节点的子节点是否存在?
即使当前节点为奇数,也有必要检查其子节点的子节点。这是因为当前节点的子节点可能是偶数,如果是偶数,根据题目要求,需要将其子节点(即当前节点的孙子节点)的值加入总和。因此,算法需要继续递归检查每个节点,以确保不遗漏任何符合条件的祖父节点。
🦆
算法中对于空节点的处理是如何实现的?基于当前代码结构,如果节点为空,是否有可能导致程序错误?
在当前的解决方案中,对于空节点的处理是通过检查节点是否存在来实现的。例如,在尝试访问一个节点的左或右子节点之前,会先检查该节点是否存在。如果节点为空,则不会进行任何操作或递归调用,这样可以防止空引用异常。因此,基于当前的代码结构,对空节点的处理是安全的,不会导致程序错误。
🦆
在递归函数中,为什么需要在每一步都重新计算子树的总和而不是传递累加值?这样的设计有什么优点或缺点?
在递归函数中,每一步重新计算子树的总和而不是传递累加值,这样做的优点是每个递归调用都是独立的,不依赖于外部状态,这使得代码更加简洁和易于理解。缺点是可能会增加计算的重复性,因为每个节点的值可能会在多个递归调用中被重复计算。不过,在此问题中,由于每个节点的贡献依据其祖父节点的状态而定,这种设计确保了计算的正确性。
🦆
函数中的基础情况处理(即叶子节点返回0)是否是必要的?叶子节点的存在为什么会影响到最终结果的计算?
函数中的基础情况处理是必要的,因为叶子节点没有子节点,因此也就没有孙子节点。如果叶子节点的父节点是偶数,即使这个叶子节点也是偶数,它也不会对最终结果有贡献,因为它没有孙子节点。这种处理确保了递归在正确的终止条件下停止,防止了不必要的递归调用,提高了效率。

相关问题