当前位置: 首页 > article >正文

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

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

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步之后执行递归出口,因为需要把叶子节点的值加上。

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

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,无需判断其右子树。

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


http://www.kler.cn/a/464928.html

相关文章:

  • 《learn_the_architecture_-_aarch64_exception_model》学习笔记
  • node.js:多线程 简单示例
  • spring mvc源码学习笔记之五
  • XIAO ESP32 S3网络摄像头——2视频获取
  • 电脑里msvcr120.dll文件丢失怎样修复?
  • MATLAB程序转C# WPF,dll集成,混合编程
  • 欧科云链研究院:ChatGPT 眼中的 Web3
  • 深入研究.NET 中的 CLR
  • 存储对象之【视图】
  • [网络安全] DVWA之Content Security Policy (CSP) Bypass 攻击姿势及解题详析合集
  • Golang 如何打包到Docker运行
  • 小程序组件 —— 25 组件案例 - 商品导航区域
  • df.replace({‘b‘: r‘\s*\.\s*‘}, {‘b‘: np.nan}, regex=True)
  • (六)vForm 动态表单(数据量大,下拉选卡顿问题)
  • C# 服务调用RFC函数获取物料信息,并输出生成Excel文件
  • 【商业化】【微软商店】微软打包时报找不到img/logo.ico
  • java class类对象 加载时机
  • 深度学习blog- 数学基础(全是数学)
  • 【每日学点鸿蒙知识】组件对象做参数、2D在子线程中使用、Tabs组件联动、Web组件获取焦点、Text加载藏文
  • EasyPlayer.js RTSP流重连问题的说明
  • Unity2D无限地图的实现(简单好抄)
  • 【Docker】:Docker命令及平台基本使用方法
  • C++ 空类大小
  • Tailwind CSS 实战:动画效果设计与实现
  • el-table 实现纵向多级表头
  • canvas+fabric实现时间刻度尺+长方形数据展示