【递归、搜索与回溯】二叉树的深搜

这篇博客记录了关于二叉树深搜的几道题目,包括求根节点到叶节点数字之和、二叉树剪枝、验证二叉搜索树、二叉树的所有路径。

cpp 复制代码
class Solution {
public:
    int sumNumbers(TreeNode* root) 
    {
        return dfs(root,0);
    }
    int dfs(TreeNode* root, int presum)
    {
        presum = presum*10 + root->val;
        if(!root->left && !root->right) return presum;
        int left = 0, right = 0;
        if(root->left) left = dfs(root->left, cursum);
        if(root->right) right = dfs(root->right, cursum);
        return left + right;
    }
};

题目分析:如下图所示,假设我们递归到5时,只需关注要干什么事情才能达到目的,此时需要拿到1258、12594、125931,然后向上返回它们之和。在递归到5时,需要接收传入之前路径的数字即12,以便计算最终结果。当拿到12后,需要加上当前节点值即125,传给左边得到1258,左边返回来1258,;传给右边得到1259,返回来12594+125931。然后把左边和右边返回值之和返回给上面。

因此,我们可以得到递归函数:

1.函数头:int dfs(root, presum),其返回值是以当前根结点所有相连之和。

2.函数体:执行1234。

3.递归出口:遇到叶子节点。并且是在第1步之后执行递归出口,因为需要把叶子节点的值加上。

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) 
        {
            //delete root;
            root = nullptr;
        }
        return root;
    }
};

题目分析 :这道题的子问题是给一棵树的头指针,返回删除后的指针。给一个节点,只有知道左子树的信息和右子树的信息之后,才能决定当前节点要不要被剪掉,因此是一个后序遍历

1.函数头:Node* dfs(root)

2.函数体:

1)处理左子树

2)处理右子树

3)判断左子树和右子树是不是空,并且本身是不是空

3.递归出口:root==nullptr,返回nullptr

cpp 复制代码
class Solution 
{
    long long prev = LONG_MIN;
public:
    bool isValidBST(TreeNode* root) 
    {
        if(root == nullptr) return true;
        bool left = isValidBST(root->left);
        //剪枝
        if(left == false) return false;
        bool cur = false;
        if(root->val > prev) cur = true;
        //剪枝
        if(cur == false) return false;
        prev = root->val;
        bool right = isValidBST(root->right);
        return left && cur && right;  
    }
};

题目分析:我们用到二叉搜索树的中序遍历结果是一个有序的序列。为此,我们可以搞一个前驱的全局变量prev,初始化为LONG_MIN(由于这道题给的数据范围,不能初始化为INT_MIN),这个全局变量的意思就是在遍历到某一个位置后,这个位置的前驱是多少,只需要判断当前位置的值和prev大小,只有当前位置的值大于prev时才符合要求。

为了解决这道题,我们有两个策略:

1.左子树是二叉搜索树,当前节点也是二叉搜索树,右子树也是二叉搜索树。

2.剪枝。在1的基础上,如果某个左子树不符合要求,就可以直接返回false,无需判断上一节点和其右子树。同理,如果当前节点不符合要求,直接返回false,无需判断其右子树。

cpp 复制代码
class Solution 
{
    vector<string> ret;
    string path;
public:
    vector<string> binaryTreePaths(TreeNode* root) 
    {
        dfs(root,path);
        return ret;
    }
    void dfs(TreeNode* root, string path)
    {
        if(root == nullptr) return;
        if(root->left == nullptr && root->right == nullptr)
        {
            path += to_string(root->val);
            ret.push_back(path);
            return;
        }
        else
        {
            path += to_string(root->val);
            path += "->";
            dfs(root->left, path);
            dfs(root->right, path);
        }
    }
};

题目分析:这道题需要创建一个全局变量ret,另外需要将path作为参数传入dfs,这样在回溯时就不需要"恢复现场"。

函数头:void dfs(root, path)

函数体:if(root == 叶子节点)不需要加->;

if(root != 叶子节点)需要加->;

相关推荐
hold?fish:palm7 小时前
24 回文链表
数据结构·c++·链表
qeen8710 小时前
【数据结构】自平衡二叉搜索树各种旋转算法原理解析及AVL树的C++实现
数据结构·c++·算法
冻柠檬飞冰走茶11 小时前
PTA基础编程题目集 7-35有理数均值(C++语言实现)
开发语言·数据结构·c++·算法·均值算法
Nil20813 小时前
leetcode 189轮转数组
数据结构·算法·leetcode
依然鸣14 小时前
PTA团体程序设计天梯赛L1真题讲解L1-085-088
数据结构·c++·经验分享·算法·深度优先·pat考试
Brilliantwxx15 小时前
【算法从零到千】【51-54】逆序对(分治+递归算法)
数据结构·算法·排序算法
小星星闪亮登场15 小时前
2026河南萌新联赛第四场--南阳理工学院
数据结构·算法·贪心算法·动态规划·哈希算法·广度优先
土司大王15 小时前
LeetCode hot100——两数之和
数据结构·算法·leetcode
wabs66616 小时前
关于字符串【力扣344.反转字符串的思考】
数据结构·算法·leetcode
LuminousCPP16 小时前
数据结构基础篇(二):顺序表与链表全方位对比|从内存布局到 CPU 缓存理解底层差异
c语言·数据结构·经验分享·链表·缓存