
个人主页 :1白天的黑夜1-CSDN博客
专栏:力扣刷题录_1白天的黑夜1的博客-CSDN博客、企鹅程序员:Linux 系统与网络编程_1白天的黑夜1的博客-CSDN博客
目录
[根据上面的分析结合自己的思路,先去尝试编写代码,多动手敲代码才能有效提高自己的代码水平。题目链接如下:814. 二叉树剪枝 - 力扣(LeetCode)](#根据上面的分析结合自己的思路,先去尝试编写代码,多动手敲代码才能有效提高自己的代码水平。题目链接如下:814. 二叉树剪枝 - 力扣(LeetCode))
看到最后,如果对您有所帮助,还请点赞、收藏和关注一键三连,在未来还会继续带来优秀的内容,感谢观看,我们下期再见!
一、题目解析

返回移除了所有不包含1的子树的原二叉树这句话不是很好理解,我们可以变成意思相同的另一句话--返回移除了所有只包含0的子树的原二叉树。从示例1我们也能发现,不是只要有0就删掉,子树必须全为0才能剪去。由于是原二叉树,所以我们需要在原二叉树上修改,并返回原本的根节点。
二、算法原理
解法:递归

这个图我们该怎么判断剪枝?

类比后序遍历,左子树,右子树,根的访问顺序。此时左边节点值为0的节点肯定是需要剪枝的,用叶子节点的判断条件+val值为0即可找到要剪枝的节点,并将其修改为nullptr完成剪枝。叶子节点也就是左右子树为空的节点,即root->left == root->right == nullptr。
如果有三个0值节点在同一子树该怎么办?

依旧左子树,右子树,根的处理方式,我们可以发现在把左右子树剪枝后,剩下的根成为了叶子节点,所以可以继续使用之前的剪枝逻辑。
接下来我们根据我们的分析,抽象出递归的三个核心问题
1、重复的子问题--设计函数头
我们需要遍历所有节点判断是否剪枝,所以我们需要一个参数接收传入的根节点,并且我们还需要返回原二叉树,所以还需要一个返回值。函数头类似 Node* f(Node* root)。
2、只关心某一个子问题做什么--设计函数体
2.1、首先我需要去看看我的左子树是否剪枝
2.2、然后我再去看看我的右子树是否剪枝
2.3、最后判断如果我是叶子节点且val值为0,返回nullptr,否则返回root
3、递归出口
由于我们会遍历节点的左右子树,如果遍历的是叶子节点的左右子树,因为是nullptr,所以不用继续向下遍历,所以返回nullptr
细节:
如何保证剪枝成功?
利用递归函数的返回值,假如判断为叶子节点,通过返回值nullptr,将对应的左子树or右子树的值修改,类似 root->left = f(root->left),如果不是叶子节点,返回的也是root->left本身
根据上面的分析结合自己的思路,先去尝试编写代码,多动手敲代码才能有效提高自己的代码水平。题目链接如下:814. 二叉树剪枝 - 力扣(LeetCode)
三、代码示例
cpp
class Solution {
public:
TreeNode* pruneTree(TreeNode* root)
{
if(root == nullptr) return nullptr;
root->left = pruneTree(root->left);//根据返回值剪枝
root->right = pruneTree(root->right);
if(root->left == nullptr && root->right == nullptr && root->val == 0) return nullptr;
else return root;
}
};

四、递归展开图
简单模拟一下,感兴趣的读者可以找一张a4纸或者打开画图软件自己动手画一画
