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

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

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 != 叶子节点)需要加->;

相关推荐
双叶8362 小时前
(C语言)写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和(递归函数)
c语言·开发语言·数据结构·算法·游戏
阿饼2402 小时前
算法——层序遍历和中序遍历构造二叉树
数据结构·算法
小咖拉眯5 小时前
蓝桥杯进制问题秒破解法|冲击省一题单(二)
java·数据结构·算法·蓝桥杯
এ旧栎6 小时前
蓝桥与力扣刷题(蓝桥 星期计算)
java·数据结构·算法·leetcode·职场和发展·蓝桥杯·规律
九转苍翎7 小时前
Java Collection(3)——BinaryTree(二叉树)
java·数据结构
Archer1947 小时前
C++基础——从C语言快速入门
数据结构·c++·算法
好易学数据结构7 小时前
可视化图解算法:链表中环的入口节点(环形链表 II)
数据结构·算法
_星辰大海乀8 小时前
刷题练习笔记
java·数据结构·笔记·算法·链表·list·idea
yadanuof10 小时前
leetcode hot100特殊题型
数据结构·算法·leetcode
print('name')11 小时前
将景区天气数据存储到Excel文件中
开发语言·数据结构·python·pycharm·excel·visual studio code