深搜(二叉树剪枝)(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,当前节点也保留。

相关推荐
HABuo2 小时前
【linux网络(一)】初识网络, 理解协议&四层网络模型&网络传输流程
linux·运维·服务器·网络·c++·ubuntu·centos
流年如夢2 小时前
结构体:定义、使用与内存布局
c语言·开发语言·数据结构·c++·算法
wuminyu2 小时前
专家视角看 Java 字节码与Class 文件格式
java·linux·c语言·jvm·c++
键盘会跳舞2 小时前
【Qt】分享一个笔者持续更新的项目: https://github.com/missionlove/NQUI
c++·qt·用户界面·qwidget
曼巴UE52 小时前
UE 客户端 需要的网络同步概念总结
网络·c++·ue5
『昊纸』℃2 小时前
C语言学习心得集合 篇1
c语言·算法·编程基础·学习心得·实践操作
云深麋鹿2 小时前
C++ | 继承
开发语言·c++
小辉同志2 小时前
Epoll+线程池
开发语言·c++·c·线程池·epoll
史迪仔01122 小时前
[QML] Qt Quick Dialogs 模块使用指南
开发语言·前端·c++·qt