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

【递归、搜索与回溯算法】深度优先搜索

在这里插入图片描述

  • 深度优先遍历 VS 深度优先搜索
  • 一、[计算布尔二叉树的值](https://leetcode.cn/problems/evaluate-boolean-binary-tree/description/)
  • 二、[求根节点到叶节点数字之和](https://leetcode.cn/problems/sum-root-to-leaf-numbers/description/)
  • 三、[二叉树剪枝](https://leetcode.cn/problems/binary-tree-pruning/description/)
  • 四、[验证二叉搜索树](https://leetcode.cn/problems/validate-binary-search-tree/description/)
  • 五、[二叉搜索树中第 K 小的元素](https://leetcode.cn/problems/kth-smallest-element-in-a-bst/description/)
  • 六、[二叉树的所有路径](https://leetcode.cn/problems/binary-tree-paths/description/)
  • 结尾

深度优先遍历 VS 深度优先搜索

  • 深度优先遍历:按照深度优先的顺序访问结构中的所有节点
  • 深度优先搜索:在一个状态空间(如迷宫、图、决策树)中寻找满足特定条件的解,可能不需要遍历所有节点,找到解后可提前终止。

遍历是形式,搜索是目的。

  • 遍历强调 “按规则走一遍”,深度优先遍历规定了 “先深入一条路,再回溯” 的访问顺序。这种形式是中性的,本身不带有明确的目标,只是确保覆盖所有元素
  • 搜索则是 “带着目的去遍历”,比如在图中找两个节点的路径、在树中找某个值的节点、在迷宫中找出口 —— 本质上是利用遍历的形式,在访问元素的过程中判断是否满足目标条件,一旦找到就可以停止(或继续寻找所有解)

一、计算布尔二叉树的值

题目描述
在这里插入图片描述

思路讲解
本道题需要我们计算布尔二叉树的值,那么首先我们就要计算根节点的左子树的布尔值和右子树的布尔值,而左右子树的布尔值又需要根据它们的左右子树的布尔值计算得来,所以本道题可以使用递归来实现。
在这里插入图片描述
以下是具体思路:

  • 终止条件
    • 若当前节点是叶子节点(没有左右孩子),直接返回其值(True 对应 1,False 对应 0)
  • 递归逻辑
    • 对于非叶子节点,先递归计算左子树的值(left_val)和右子树的值(right_val)
    • 根据当前节点的运算符(2 表示 OR,3 表示 AND),对 left_val 和 right_val 进行逻辑运算:
      • 若节点值为 2(OR):结果为 left_val OR right_val
      • 若节点值为 3(AND):结果为 left_val AND right_val
  • 返回结果
    • 返回当前节点的运算结果,供上层节点使用

编写代码

/*** 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:bool evaluateTree(TreeNode* root) {if(root->left == nullptr && root->right == nullptr)return root->val;bool left = evaluateTree(root->left);bool right = evaluateTree(root->right);return root->val == 2 ? left | right : left & right;}
};

二、求根节点到叶节点数字之和

题目描述
在这里插入图片描述

思路讲解
本道题需要我们求根节点到叶节点数字之和,那么就需要记录根节点到当前节点形成的数字,通过将数字传递给左右子树,让左右子树形成新的数字,再让左右子树将数字传递给它们的左右子树,直到到了叶子节点,将形成的数字返回,通过层层递归将左右子树返回的值相加即可完成本道题。

在这里插入图片描述
以下是具体思路:

  • 递归参数
    • 除了当前节点,还需要一个参数 prveSum 记录从根节点到当前节点的路径所形成的数字
  • 终止条件
    • 当遇到叶节点时,计算从根节点到当前节点的路径所形成的数字 currentSum ,并返回该值
  • 递归逻辑
    • 对于非叶节点,更新 currentSum:currentSum = prveSum * 10 + 当前节点值
    • 递归遍历左子树和右子树,将左右子树的返回值相加后返回

编写代码

/*** 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:int _sumNumbers(TreeNode* root , int prevSum) {int curSum = prevSum * 10 + root->val;if(root->left == nullptr && root->right == nullptr)return curSum;int left = 0 , right = 0;if(root->left)left = _sumNumbers(root->left , curSum);if(root->right)right = _sumNumbers(root->right , curSum);return left + right;}int sumNumbers(TreeNode* root) {return _sumNumbers(root,0);}
};

三、二叉树剪枝

题目描述
在这里插入图片描述

思路讲解
本道题需要我们移除了所有不包含 1 的子树,所以我们需要先判断左右子树是否可以被剪枝,左右子树也需要先判断它们的左右子树是否被剪枝,所以可以使用递归的思路完成本道题,以下是具体思路:

  • 终止条件
    • 若当前节点为空,直接返回空
  • 递归逻辑
    • 先递归剪枝左子树和右子树,得到修剪后的左、右子树新节点
  • 判断当前子树是否保留
    • 若当前节点值为 0,且修剪后的左、右子树均为空(说明整个子树没有 1),则移除当前子树,返回空
    • 否则,保留当前节点,将其左、右指针指向修剪后的子树,返回当前节点

编写代码

/*** 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);return root->left == nullptr && root->right == nullptr && root->val == 0 ? nullptr : root;}
};

四、验证二叉搜索树

题目描述
在这里插入图片描述

思路讲解
本道题需要我们验证二叉树是否为二叉搜索树,这里就可以利用二叉搜索树的特性,也就是二叉树的中序遍历是有序的,来判断是否为二叉搜索树,以下是具体思路:

  • 核心逻辑
    • 二叉搜索树的中序遍历结果是严格递增的序列。若遍历结果中出现非递增情况(如后一个元素 <= 前一个元素),则不是有效的二叉搜索树
  • 状态记录
    • 用一个变量记录上一个访问的节点值
  • 递归逻辑
    • 中序遍历左子树,过程中检查是否已出现非递增情况,出现说明该子树不是搜索二叉树,返回 false
    • 访问当前节点,与前一个访问的节点值比较:若当前节点值 ≤ 前一个节点值,说明该子树不是搜索二叉树,返回 false
    • 中序遍历右子树,同样传递比较状态

编写代码

/*** 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 {long long prev = LLONG_MIN;
public:bool isValidBST(TreeNode* root) {if(root == nullptr) return true;bool left = isValidBST(root->left);if(!left || root->val <= prev) return false;prev = root->val;return isValidBST(root->right);}
};

五、二叉搜索树中第 K 小的元素

题目描述
在这里插入图片描述

思路讲解
本道题需要我们找到二叉搜索树中第 K 小的元素,依旧是利用二叉搜索树中序遍历是有序的特性,找到第K小的元素。以下是具体思路:

  • 核心逻辑
    • 二叉搜索树的中序遍历会得到一个递增序列,第 k 个被访问的节点就是第 k 小的元素
  • 递归逻辑
    • 中序遍历左子树,过程中减少还需要访问的节点数量
    • 若已找到第 k 个节点,直接返回结果
    • 访问当前节点,将计数减1 ;若计数等于 0,当前节点即为目标,返回其值
    • 中序遍历右子树,过程中减少还需要访问的节点数量
  • 终止条件
    • 当计数为 0 时,终止遍历并返回对应节点值

编写代码

/*** 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 {int cnt , ans;
public:void _kthSmallest(TreeNode* root) {if(root == nullptr || cnt == 0) return;_kthSmallest(root->left);cnt--;if(cnt == 0) ans = root->val;_kthSmallest(root->right);}int kthSmallest(TreeNode* root, int k) {cnt = k;_kthSmallest(root);return ans;}
};

六、二叉树的所有路径

题目描述
***

思路讲解
本道题需要我们找出二叉树的所有路径,也就是我们需要遍历一遍二叉树,并且记录当前路径,当遍历到叶子节点的时候,将当前路径加入到结果集中,以下是具体思路:

  • 函数参数
    • 当前节点,也就是子树的根节点
    • 记录从根节点到当前节点的路径
  • 终止条件
    • 当遇到叶子节点时,将当前路径加入完整路径的结果集并返回
  • 递归逻辑
    • 若当前节点不是叶子节点,更新当前路径:拼接当前节点值和 “->”
    • 递归遍历左子树,传递更新后的当前路径
    • 递归遍历右子树,传递更新后的当前路径

编写代码

/*** 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 {vector<string> ans;
public:void _binaryTreePaths(TreeNode* root , string path){path += to_string(root->val);if(root->left == nullptr && root->right == nullptr){ans.push_back(path);return;}path += "->";if(root->left) _binaryTreePaths(root->left , path);if(root->right) _binaryTreePaths(root->right , path); }vector<string> binaryTreePaths(TreeNode* root) {_binaryTreePaths(root,string());return ans;}
};

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹
在这里插入图片描述

http://www.dtcms.com/a/324312.html

相关文章:

  • Text2SQL 自助式数据报表开发(Chat BI)
  • 《解锁 C++ 起源与核心:命名空间用法 + 版本演进全知道》
  • Spring Boot 注解详解:@RequestMapping 的多种用法
  • Docker 跨主机容器之间的通信macvlan
  • 攻击实验(ARP欺骗、MAC洪范、TCP SYN Flood攻击、DHCP欺骗、DHCP饿死)
  • Spring Boot与WebSocket构建物联网实时通信系统
  • LeetCode 子集
  • Java基础-Map接口
  • 香橙派 RK3588 部署 DeepSeek
  • SQL约束:数据完整性的守护者
  • Linux中rsync数据镜像工具的解析与应用实战
  • 如何在 Ubuntu 24.04 LTS Linux 上安装 MySQL 服务器
  • JavaScript防抖与节流:拯救你的网页卡顿危机!
  • GitHub 趋势日报 (2025年08月09日)
  • 通过Certbot自动申请更新HTTPS网站的SSL证书
  • vue中使用h5plus
  • 一些js数组去重的实现算法
  • 黑马SpringBoot+Elasticsearch作业2实战:商品搜索与竞价排名功能实现
  • 使用正则表达式检测Base64字符串并提取图片类型及正文的JavaScript函数,代码精简且高效
  • 250810-OpenWebUI集成Dify应用
  • 《设计模式》策略模式
  • STM32的计数模式和pwm模式
  • 亚麻云之数据安家——RDS数据库服务入门
  • sqli-labs-master/Less-62~Less-65
  • 01.【面试题】在SpringBoot中如何实现多数据源配置
  • (Python)爬虫进阶(Python爬虫教程)(CSS选择器)
  • 2025年全国青少年信息素养大赛Scratch编程践挑战赛-小低组-初赛-模拟题
  • Linux系统编程Day11 -- 进程状态的优先级和特性
  • 移动端音频处理实践:59MB变声应用的技术实现分析
  • 机器学习-增加样本、精确率与召回率