
🔥小叶-duck:个人主页
❄️个人专栏:《Data-Structure-Learning》
✨未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游
目录
8.⼆叉树剪枝
题目链接:
题目描述:

题目示例:

解法(dfs-后序遍历):
后序遍历按照左子树、右子树、根节点的顺序遍历二叉树的所有节点,通常用于父节点的状态依赖于子节点状态的题目。
算法思路:
如果我们选择从上往下删除,我们需要收集左右子树的信息,这可能导致代码编写相对困难。然而,通过观察我们可以发现,如果我们先删除最底部的叶子节点,然后再处理删除后的节点,最终的结果并不会受到影响。
因此,我们可以采用后序遍历的方式来解决这个问题。在后序遍历中,我们先处理左子树,然后处理右子树,最后再处理当前节点 。在处理当前节点时,我们可以判断其是否为叶子节点且其值是否为0 ,如果满足条件,我们可以删除当前节点(置空)。
需要注意的是,在删除叶子节点时,其父节点很可能会成为新的叶子节点。因此,在处理完子节点后,我们仍然需要处理当前节点。这也是为什么选择后序遍历的原因(后序遍历首先遍历到的一定是叶子节点)。
通过使用后序遍历,我们可以逐步删除叶子节点,并且保证删除后的节点仍然满足删除操作的要求。这样,我们可以较为方便地实现删除操作,而不会影响最终的结果。
若在处理结束后所有叶子节点的值均为1,则所有子树均包含1,此时可以返回。
C++算法代码:
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)
{
//递归结束条件:当为空结点时则进行返回
if(root == nullptr)
{
return nullptr;
}
root->left = pruneTree(root->left);
root->right = pruneTree(root->right);
//左右子树完成剪枝后,还需要判断当前结点本身值是否为0
//如果结点本身为0且左右子树全为空说明需要删除(结点置为nullptr)
if(root->val == 0 && root->left == nullptr && root->right == nullptr)
{
root = nullptr;
}
//如果左右子树其中一个不是空(存在结点值为1)或者当前结点值为1,则不需要删除
return root;
}
};
算法总结及流程解析:

9.验证二叉搜索树
题目链接:
题目描述:

题目示例:

解法(利用中序遍历):
中序遍历 按照左子树、根节点、右子树的顺序遍历二叉树的所有节点,通常用于二叉搜索树相关题目。
算法思路:
如果一棵树是二叉搜索树 ,那么它的中序遍历的结果一定是一个严格递增的序列 。
因此,我们可以初始化一个无穷小的全区变量prev ,用来记录中序遍历过程中的前驱结点 。那么就可以在中序遍历的过程中,先判断是否和前驱结点构成递增序列 ,然后修改前驱结点为当前结点,传入下一层的递归中。
C++算法代码(无剪枝版本):
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:
//用一个全局变量来记录中序遍历过程中是否有序
long prev = LONG_MIN;
bool isValidBST(TreeNode* root)
{
//判断是否为二叉搜索树方法:利用中序遍历判断是否有序
//递归结束条件:当前结点为空则也是二叉搜索树,返回true
if(root == nullptr)
{
return true;
}
bool left = isValidBST(root->left);
//此时左子树已经判断完了,则轮到当前结点的值和prev进行判断
bool cur = false;
if(prev < root->val)
{
prev = root->val;
cur = true;
}
bool right = isValidBST(root->right);
//此时当前结点的右子树已经判断完了,则判断以当前结点为头是否为二叉搜索树
if(left && cur && right)
{
return true;
}
return false;
}
};
C++算法代码(剪枝版本):
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:
//用一个全局变量来记录中序遍历过程中是否有序
long prev = LONG_MIN;
bool isValidBST(TreeNode* root)
{
if(root == nullptr)
{
return true;
}
bool left = isValidBST(root->left);
//此时当前结点的左子树已经判断完了
//但如果判断完左子树发现已经不是二叉搜索树了,
//则无需再将结点的值和prev比较,以及判断结点的右子树了(剪枝)
if(left == false)
{
return false;
}
bool cur = false;
if(prev < root->val)
{
prev = root->val;
cur = true;
}
else
{
//如果当前结点值大于等于prev,说明不是有序的
//就不符合二叉搜索树,则无需再判断结点的右子树了(剪枝)
return false;
}
bool right = isValidBST(root->right);
if(left && cur && right)
{
return true;
}
return false;
}
};
算法总结及流程解析:

结束语
到此,8.二叉树剪枝,9.验证二叉搜索树 这两道算法题就讲解完了。**二叉树剪枝 采用后序遍历方法,先处理左右子树再判断当前节点是否为值为0的叶子节点进行删除;验证二叉搜索树 则利用中序遍历特性,通过维护前驱节点判断序列是否严格递增。提供了两种解法:完整遍历版和剪枝优化版,后者在发现不符合条件时提前终止递归。**希望大家能有所收获!