leetcode
leetcode 1001 ~ 1050
根到叶路径上的不足节点

根到叶路径上的不足节点

难度:

标签:

题目描述

给你二叉树的根节点 root 和一个整数 limit ,请你同时删除树中所有 不足节点 ,并返回最终二叉树的根节点。

假如通过节点 node 的每种可能的 “根-叶” 路径上值的总和全都小于给定的 limit,则该节点被称之为 不足节点 ,需要被删除。

叶子节点,就是没有子节点的节点。

 

示例 1:

输入:root = [1,2,3,4,-99,-99,7,8,9,-99,-99,12,13,-99,14], limit = 1
输出:[1,2,3,4,null,null,7,8,9,null,14]

示例 2:

输入:root = [5,4,8,11,null,17,4,7,1,null,null,5,3], limit = 22
输出:[5,4,8,11,null,17,4,7,null,null,null,5]

示例 3:

输入:root = [1,2,-3,-5,null,4,null], limit = -1
输出:[1,null,-3,4]

 

提示:

  • 树中节点数目在范围 [1, 5000]
  • -105 <= Node.val <= 105
  • -109 <= limit <= 109

 

代码结果

运行时间: 41 ms, 内存: 17.6 MB


/*
 * In this Java Stream solution, we cannot directly use streams to handle tree traversal due to their recursive nature.
 * However, the logic remains similar, and we'll use traditional recursive methods but explain using Stream API concepts.
 * This solution involves traversing the tree using a recursive function that calculates the maximum path sum from the root to any leaf.
 */
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    public TreeNode sufficientSubset(TreeNode root, int limit) {
        return dfs(root, 0, limit);
    }
    private TreeNode dfs(TreeNode node, int sum, int limit) {
        if (node == null) return null;
        sum += node.val;
        if (node.left == null && node.right == null) {
            return sum < limit ? null : node;
        }
        node.left = dfs(node.left, sum, limit);
        node.right = dfs(node.right, sum, limit);
        return node.left == null && node.right == null ? null : node;
    }
}

解释

方法:

这个题解使用了递归的方式处理每个节点,以判断是否保留或删除该节点。首先,每次递归调用都会从limit中减去当前节点的值,然后检查当前节点是否为叶子节点(即同时没有左右子节点)。对于叶子节点,如果剩余的limit值大于0,说明这条路径的总和不足,因此需要删除这个叶子节点。对于非叶子节点,递归地调用左右子节点,更新当前节点的左右子节点引用。最后,如果一个节点的左右子节点都被删除了,说明这个节点也变成了不足节点,因此也应该被删除。整个过程从根节点开始递归地处理,直到所有的不足节点都被删除。

时间复杂度:

O(n)

空间复杂度:

O(h),其中h是树的高度。在最坏的情况下,这可以达到O(n)。

代码细节讲解

🦆
递归函数中对剩余的limit进行减少时,为什么选择减去当前节点的值而不是其他数值?
在这个问题中,目的是确保从根节点到任何叶子节点的路径上的节点值之和至少达到一个给定的limit。因此,每次递归调用时减去当前节点的值是为了跟踪从根节点到当前节点的累积和。这样,当到达叶子节点时,我们可以直接通过检查剩余的limit(即目标值减去路径上已累计的和)是否大于0来判断该路径的总和是否不足。如果选择减去其他数值,则无法正确地跟踪并判断是否满足条件。
🦆
在递归删除节点的过程中,如果某个节点的一个子节点被删除,但另一个子节点没有被删除,这种情况下该如何处理当前节点?
在这种情况下,当前节点不会被删除。根据题解的逻辑,只有当一个节点的所有子节点都被删除时,该节点才会被考虑删除。如果一个节点至少有一个子节点没有被删除,那么这个节点仍然保留在树中,因为它至少有一条从它到叶子节点的有效路径,即路径总和达到或超过了给定的limit。
🦆
根据题目的逻辑,如果根节点自身就是一个不足节点,返回的结果会是什么?
如果根节点自身就是一个不足节点,这意味着从根节点到任何叶子节点的路径之和都不能满足给定的limit条件。在这种情况下,整个树都会被视为不足,因此根据题解的逻辑,返回的结果会是None,表示整棵树都被删除了。
🦆
递归调用的终结条件是什么?是否可能出现栈溢出的情况,特别是在处理极端不平衡的大树时?
递归调用的终结条件是当遇到叶子节点时(即节点同时没有左右子节点)。在这种情况下,会根据剩余的limit值来决定是否删除该叶子节点。关于栈溢出的可能性,虽然在极端不平衡的大树中递归深度可能非常高,但Python通常能够处理相对较深的递归调用。不过,对于特别大的数据或极端情况,确实存在栈溢出的风险,这时可以考虑使用迭代方法或增加递归调用的最大深度。

相关问题