深搜(二叉树剪枝)(3)

一.题目

814. 二叉树剪枝 - 力扣(LeetCode)

二.思路讲解

2.1 审题

本题要求对一棵二叉树进行剪枝 ,其中每个节点的值只能是 01 。剪枝的规则是:如果一棵子树中所有节点的值都为 0 ,那么将这棵子树整个移除。换句话说,我们需要从叶子节点向上检查,如果某个节点及其所有后代都不包含 1,则将该节点置为 nullptr,使其父节点不再指向它。

2.2 子问题解决

对于二叉树的问题,我们通常采用后序遍历的方式,因为要先知道左右子树的情况,才能决定当前节点是否需要被剪掉。具体思路如下:

  • 首先,递归地处理左子树右子树,得到它们剪枝后的结果。这一步我们相信递归能正确完成。

  • 然后,检查当前节点:如果左子树剪枝后为空右子树剪枝后为空当前节点的值本身为 0 ,说明以当前节点为根的整棵子树都不包含 1,那么应该将当前节点删除,即返回 nullptr 给父节点。

  • 否则,当前节点需要保留,并连接上剪枝后的左右子树,然后返回当前节点。

通过这种方式,我们自底向上地完成了剪枝,且每个节点只需要访问一次。

2.3 递归终止条件

递归的终止条件是当节点为空(nullptr)时,直接返回 nullptr。因为空节点既没有值也不属于任何子树,作为递归的基础情况非常自然。

三.代码演示

cpp 复制代码
/**
 * Definition for a binary tree node.
 * 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:
    TreeNode* pruneTree(TreeNode* root) 
    {
        //1.终止条件
        if(root == nullptr)
            return nullptr;
        //2.子问题解决
        root->left = pruneTree(root->left);
        root->right = pruneTree(root->right);
        if(root->left == nullptr && root->right == nullptr && root->val == 0)
        {
            return nullptr;
        }
        return root;
    }
};

四.代码讲解

一、递归函数设计

我们定义递归函数 pruneTree(TreeNode* root) ,它的含义是:对以 root 为根的二叉树进行剪枝,并返回剪枝后新的根节点(可能为 nullptr)。剪枝规则是移除所有不包含 1 的子树。由于我们需要先知道左右子树的情况才能决定当前节点是否保留,因此采用后序遍历的方式。

二、递归终止条件

当当前节点为空(root == nullptr)时,直接返回 nullptr。这是递归的基础情况,因为空节点自然不需要剪枝,也没有任何值。

三、递归步骤分解

对于非空节点,按照以下步骤进行后序遍历:

  1. 递归处理左子树 调用 pruneTree(root->left) 对左子树进行剪枝,并将结果重新赋值给 root->left。这一步会移除左子树中所有全零子树,返回剪枝后的左子节点(可能为空)。我们相信递归能正确完成

  2. 递归处理右子树 同理,调用 pruneTree(root->right) 对右子树剪枝,结果赋给 root->right

  3. 判断当前节点是否需要被移除 在左右子树都处理完毕后,检查当前节点是否满足移除条件 :左子树为空、右子树为空、且当前节点的值为 0。如果三者同时成立,说明以当前节点为根的整棵子树都不包含 1,因此应该将当前节点移除,返回 nullptr 给父节点。

  4. 返回保留的节点 如果不满足移除条件,则当前节点需要保留,直接返回 root。此时它的左右子树已经过剪枝,结构正确。

四、关键细节
  • 后序遍历的必要性:只有先知道左右子树是否为空,才能判断当前节点是否应该被删除。这是由剪枝规则决定的。。

  • 指针更新 :通过 root->left = pruneTree(root->left) 的方式,将剪枝后的子树直接挂回当前节点,实现了原地修改。

  • 移除条件:注意条件是左右子树都为空且当前节点值为0,这意味着整棵子树都无1。如果当前节点值为1,即使左右为空也保留;如果某子树非空,说明该子树有1,当前节点也保留。

相关推荐
chao1898445 小时前
基于 SPEA2 的多目标优化算法 MATLAB 实现
开发语言·算法·matlab
沪漂阿龙5 小时前
AI大模型面试题:支持向量机是什么?间隔最大化、软间隔、核函数、LinearSVC 全面拆解
人工智能·算法·支持向量机
難釋懷5 小时前
Redis数据结构-Set结构
数据结构·redis·bootstrap
little~钰5 小时前
倍增算法和ST表
算法
知识领航员6 小时前
蘑兔AI音乐深度实测:功能拆解、实测表现与适用场景
java·c语言·c++·人工智能·python·算法·github
薛定e的猫咪6 小时前
因果推理研究方向综述笔记
人工智能·笔记·深度学习·算法
如何原谅奋力过但无声7 小时前
【灵神高频面试题合集06-08】反转链表、快慢指针(环形链表/重排链表)、前后指针(删除链表/链表去重)
数据结构·python·算法·leetcode·链表
平行侠7 小时前
037插入排序 - 整理扑克牌的算法
数据结构·算法
ECT-OS-JiuHuaShan8 小时前
彻底定理化:从量子纠缠到量子代谢
数据库·人工智能·学习·算法·生活·量子计算