题目9:1080. 根到叶路径上的不足节点
同类题目
无
前置知识
- 无
题目描述
给你二叉树的根节点 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
思路分析
节点的删除判断
叶子节点: 根到叶子的路径仅有一条,如果这条路径的元素和小于 limit 那么该节点可以删除。
非叶子节点:当且仅当左右子节点都删除,该节点才应该删除,换句话说只要孩子结点有一个被保留,父亲结点就不能被删。当前节点的左子树的所有叶子节点均为「不足节点」,则左孩子需要删除,否则保留。右子树同理。
从上面的分析得出本题需要使用后序遍历,因为节点的删除需要依赖左右子节点的结果。
因此,删除结点(也可以称为 “剪枝”)的过程是从下到上的。
程序代码
//https://leetcode.cn/problems/insufficient-nodes-in-root-to-leaf-paths/description/
//1080. 根到叶路径上的不足节点
#include<iostream>
#include<vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
// 返回当前节点是否应该被删除
bool travel(TreeNode* root, int limit,int sum)
{
// 判断头结点,如果传入null,那么返回false
if(root == nullptr)
{
return false;
}
// 当前为叶子节点,返回叶子节点是否大于等于limit
// sum >= limit 不删除
// sum < limit 删除
if(root->left == nullptr && root->right == nullptr)
{
sum += root->val;
return sum >=limit;
}
// 非叶子节点,把当前节点的val 加上后,传入左右子节点中
sum += root->val;
bool leftv = travel(root->left,limit,sum);
bool rightv = travel(root->right,limit,sum);
// 如果leftv 为false 删除
if(!leftv)
{
root->left = nullptr;
}
// 如果rightv 为false 删除
if(!rightv)
{
root->right = nullptr;
}
// 返回给父节点,当前节点是否可以删除
return leftv || rightv;
}
TreeNode* sufficientSubset(TreeNode* root, int limit) {
bool res = travel(root,limit,0);
return res ? root : nullptr;
}
};
复杂度分析
时间复杂度:O(N),其中 N 表示树中节点的数目,深度递归遍历,每个节点遍历一次。
空间复杂度:O(N),其中 N 表示树中节点的数目,最差情况下退化为单链表,高度为 N。
题目感悟
本题需要使用后序遍历,但本质上使用了「分解问题」的思路:因为当前节点接收并利用了子树返回的信息,这就意味着你把原问题分解成了当前节点 + 左右子树的子问题。
删除节点:使用父亲节点删除孩子节点的方式。
更多相关知识:github.com/pingguo1987…