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

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

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

相关推荐
終不似少年遊*1 小时前
数据结构与算法之排序
数据结构·python·算法·排序算法
James Shangguan2 小时前
LeetCode 704 如何正确书写一个二分查找
数据结构·算法·leetcode
shinelord明4 小时前
【再谈设计模式】观察者模式~对象间依赖关系的信使
开发语言·数据结构·观察者模式·设计模式·软件工程
不是仙人的闲人6 小时前
数据结构之栈和队列
数据结构·c++
米饭「」6 小时前
数据结构-双向链表
数据结构·链表
知困勉行的Allen7 小时前
MCS-51单片机常用汇编指令和特殊功能寄存器~
c语言·汇编·数据结构·单片机·嵌入式硬件·51单片机·学习方法
yuanbenshidiaos14 小时前
QT-------------多线程
数据结构·数据库·qt
疯狂成瘾者14 小时前
np.ndarray 是 NumPy 库中的核心数据结构
数据结构·numpy
南宫生14 小时前
力扣-数据结构-12【算法学习day.83】
java·数据结构·学习·算法·leetcode
快乐飒男15 小时前
数据结构(顺序表)
数据结构