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

一.题目

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

二.思路讲解

2.1 审题

本题要求对一棵二叉树进行剪枝 ,其中每个节点的值只能是 0 或 1 。剪枝的规则是:如果一棵子树中所有节点的值都为 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,当前节点也保留。

相关推荐
千千寰宇23 分钟前
[数据库系统] 数据库系统的设计原理研究
数据结构·数据库·database-opengemini/influxdb·database-dament/达梦
聪明蛋子哟31 分钟前
不仅仅是向量检索:结合知识图谱与Tool Calling的混合增强生成(Hybrid RAG)方案
人工智能·算法·知识图谱
Pniubi31 分钟前
力扣55跳跃游戏(贪心)
算法·leetcode·游戏
三月微暖寻春笋1 小时前
【和春笋一起学C++】(七十二)类模板
开发语言·c++·实例·类模板·使用类模板·数组模板
xlq223221 小时前
全面复习4
c++
jyyyx的算法博客1 小时前
传球游戏【思维】
算法
FL16238631291 小时前
关于2026年南昌大学811信号与系统最后一题电路系统解题思路
算法
殷色玫瑰1 小时前
C++ STL:map 与 set 详解——从底层红黑树到实际应用
c语言·数据结构·c++·算法·visualstudio·rpc
行者全栈架构师1 小时前
【鸿蒙心迹】鸿蒙网络请求架构实战——@ohos.net.http 到 Axios 封装、拦截器与统一错误处理(HarmonyOS 7.x)
前端·算法·架构
Tri_Function1 小时前
背包:从入门到实战
c++