【算法专题】二叉树中的深搜(DFS)

二叉树中的深搜

  • 深搜
    • 1. 计算布尔二叉树的值
    • 2. 求根节点到叶节点数字之和
    • 3. 二叉树剪枝
    • 4. 验证二叉搜索树
    • 5. 二叉搜索树中第K小的元素
    • 6. 二叉树的所有路径

深搜

深度优先遍历(DFS,全称为 Depth First Traversal),是我们树或者图这样的数据结构中常用的⼀种遍历算法。这个算法会尽可能深的搜索树或者图的分支,直到一条路径上的所有节点都被遍历完毕,然后再回溯到上一层,继续找⼀条路遍历。

在二叉树中,常见的深度优先遍历为:前序遍历、中序遍历以及后序遍历。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。并且前中后序三种遍历的唯一区别就是访问根节点的时机不同,在做题的时候,选择一个适当的遍历顺序,对于算法的理解是非常有帮助的。

1. 计算布尔二叉树的值

题目链接 -> Leetcode -2331.计算布尔二叉树的值

Leetcode -2331.计算布尔二叉树的值

题目:给你一棵 完整二叉树 的根,这棵树有以下特征:

叶子节点 要么值为 0 要么值为 1 ,其中 0 表示 False ,1 表示 True 。
非叶子节点 要么值为 2 要么值为 3 ,其中 2 表示逻辑或 OR ,3 表示逻辑与 AND 。
计算 一个节点的值方式如下:

如果节点是个叶子节点,那么节点的 值 为它本身,即 True 或者 False 。
否则,计算 两个孩子的节点值,然后将该节点的运算符对两个孩子值进行 运算 。
返回根节点 root 的布尔运算值。
完整二叉树 是每个节点有 0 个或者 2 个孩子的二叉树。
叶子节点 是没有孩子的节点。

示例 1:
输入:root = [2, 1, 3, null, null, 0, 1]
输出:true
解释:上图展示了计算过程。
AND 与运算节点的值为 False AND True = False 。
OR 运算节点的值为 True OR False = True 。
根节点的值为 True ,所以我们返回 true 。

示例 2:
输入:root = [0]
输出:false
解释:根节点是叶子节点,且值为 false,所以我们返回 false 。

提示:

  • 树中节点数目在[1, 1000] 之间。
  • 0 <= Node.val <= 3
  • 每个节点的孩子数为 0 或 2 。
  • 叶子节点的值为 0 或 1 。
  • 非叶子节点的值为 2 或 3 。

思路:通过判断节点的值来做不同的操作,如果节点的值为1或0,说明是叶子节点,返回true/false;如果节点值是2,那么返回它的左子树 || 右子树;如果节点值是3,返回它的左子树 && 右子树。

代码如下:

		/*** 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->val == 1) return true;if (root->val == 0) return false;if (root->val == 2) return evaluateTree(root->left) || evaluateTree(root->right);return evaluateTree(root->left) && evaluateTree(root->right);}};

2. 求根节点到叶节点数字之和

题目链接 -> Leetcode -129.求根节点到叶节点数字之和

Leetcode -129.求根节点到叶节点数字之和

题目:给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:

例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。

叶节点 是指没有子节点的节点。

示例 1:
输入:root = [1, 2, 3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12
从根到叶子节点路径 1->3 代表数字 13
因此,数字总和 = 12 + 13 = 25

示例 2:
输入:root = [4, 9, 0, 5, 1]
输出:1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495
从根到叶子节点路径 4->9->1 代表数字 491
从根到叶子节点路径 4->0 代表数字 40
因此,数字总和 = 495 + 491 + 40 = 1026

提示:

  • 树中节点的数目在范围[1, 1000] 内
  • 0 <= Node.val <= 9
  • 树的深度不超过 10

思路:
在前序遍历的过程中,我们可以往左右子树传递信息,并且在回溯时得到左右子树的返回值。递归函数可以帮我们完成两件事:

  1. 将父节点的数字与当前节点的信息整合到⼀起,计算出当前节点的数字,然后传递到下⼀层进行递归;
  2. 当遇到叶子节点的时候,就不再向下传递信息,而是将整合的结果向上一直回溯到根节点。

在递归结束时,根节点需要返回的值也就被更新为了整棵树的数字和。

代码如下:

		/*** 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 ret = 0;void dfs(TreeNode* root, int sum){if(root->left == nullptr && root->right == nullptr) {ret += sum;return;}if(root->left) dfs(root->left, sum * 10 + root->left->val);if(root->right) dfs(root->right, sum * 10 + root->right->val);}int sumNumbers(TreeNode* root) {dfs(root, root->val);return ret;}};

3. 二叉树剪枝

题目链接 -> Leetcode -814.二叉树剪枝

Leetcode -814.二叉树剪枝

题目:给你二叉树的根结点 root ,此外树的每个结点的值要么是 0 ,要么是 1 。

返回移除了所有不包含 1 的子树的原二叉树。

节点 node 的子树为 node 本身加上所有 node 的后代。

示例 1:
输入:root = [1, null, 0, 0, 1]
输出:[1, null, 0, null, 1]
解释:
只有红色节点满足条件“所有不包含 1 的子树”。 右图为返回的答案。

示例 2:
输入:root = [1, 0, 1, 0, 0, 0, 1]
输出:[1, null, 1, null, 1]

示例 3:
输入:root = [1, 1, 0, 1, 1, 0, 1, 0]
输出:[1, 1, 0, 1, 1, null, 1]

提示:

  • 树中节点的数目在范围[1, 200] 内
  • Node.val 为 0 或 1

思路:
如果我们选择从上往下删除,我们需要收集左右子树的信息,这可能导致代码编写相对困难。然而,通过观察我们可以发现,如果我们先删除最底部的叶子节点,然后再处理删除后的节点,最终的结果并不会受到影响。因此,我们可以采用后序遍历的方式来解决这个问题。在后序遍历中,我们先处理左子树,然后处理右子树,最后再处理当前节点。在处理当前节点时,我们可以判断其是否为叶子节点且其值是否为 0,如果满足条件,我们可以删除当前节点。

  • 需要注意的是,在删除叶子节点时,其父节点很可能会成为新的叶子节点。因此,在处理完子节点后,我们仍然需要处理当前节点。这也是为什么选择后序遍历的原因(后序遍历首先遍历到的一定是叶子节点)。
  • 通过使用后序遍历,我们可以逐步删除叶子节点,并且保证删除后的节点仍然满足删除操作的要求。这样,我们可以较为方便地实现删除操作,而不会影响最终的结果。
  • 若在处理结束后所有叶子节点的值均为 1,则所有子树均包含 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);if(root->val == 0 && root->left == nullptr && root->right == nullptr) {delete root;root = nullptr;}return root;}};

4. 验证二叉搜索树

题目链接 -> Leetcode -98.验证二叉搜索树

Leetcode -98.验证二叉搜索树

题目:给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

示例 1:
输入:root = [2, 1, 3]
输出:true

示例 2:
输入:root = [5, 1, 4, null, null, 3, 6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:
树中节点数目范围在[1, 10^4] 内

  • -2^31 <= Node.val <= 2^31 - 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 {long prev = LONG_MIN;public:bool isValidBST(TreeNode* root) {if(root == nullptr) return true;bool Left = isValidBST(root->left);if(!Left) return false; // 剪枝if(root->val <= prev) return false; //剪枝prev = root->val;  bool Right = isValidBST(root->right);return Left && Right;}};

5. 二叉搜索树中第K小的元素

题目链接 -> Leetcode -230.二叉搜索树中第K小的元素

Leetcode -230.二叉搜索树中第K小的元素

题目:给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

示例 1:
输入:root = [3, 1, 4, null, 2], k = 1
输出:1

示例 2:
输入:root = [5, 3, 6, 2, 4, null, null, 1], k = 3
输出:3

提示:
树中的节点数为 n 。

  • 1 <= k <= n <= 10^4
  • 0 <= Node.val <= 10^4

思路:我们可以根据中序遍历的过程,只需扫描前 k 个结点即可;因此,我们可以创建一个全局的计数器 count,将其初始化为 k,每遍历一个节点就将 count- -;直到某次递归的时候,count 的值等于 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 {int ret, count;public:void dfs(TreeNode* root){if(root == nullptr || count == 0) return;dfs(root->left);count--;if(count == 0) ret = root->val;dfs(root->right);}int kthSmallest(TreeNode* root, int k) {count = k, ret = 0;dfs(root);return ret;}};

6. 二叉树的所有路径

题目链接 -> 添加链接描述

Leetcode -257.二叉树的所有路径

题目:给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

叶子节点 是指没有子节点的节点。

示例 1:
输入:root = [1, 2, 3, null, 5]
输出:[“1->2->5”, “1->3”]

示例 2:
输入:root = [1]
输出:[“1”]

提示:
树中节点的数目在范围[1, 100] 内

  • 100 <= Node.val <= 100

思路:路径以字符串形式存储,从根节点开始遍历,每次遍历时将当前节点的值加入到路径中,如果该节点为叶子节点,将路径存储到结果中。否则,将 “->” 加入到路径中并递归遍历该节点的左右子树。定义一个结果数组,进行递归。递归具体实现方法如下:

  1. 如果当前节点不为空,就将当前节点的值加入路径 str 中,否则直接返回;
  2. 判断当前节点是否为叶子节点,如果是,则将当前路径加入到所有路径的存储数组 ret 中;
  3. 否则,将当前节点值加上 “->” 作为路径的分隔符,继续递归遍历当前节点的左右子节点。
  4. 返回结果数组

注意:我们可以只使用一个字符串存储每个状态的字符串,在递归回溯的过程中,需要将路径中的当前节点移除,以回到上一个节点。

代码如下:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/592190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

玩转贝启科技BQ3588C开源鸿蒙系统开发板 —— 开发板详情与规格

本文主要参考&#xff1a; BQ3588C_开发板详情-开源鸿蒙技术交流-Bearkey-开源社区 BQ3588C_开发板规格-开源鸿蒙技术交流-Bearkey-开源社区 厦门贝启科技有限公司-Bearkey-官网 1. 开发板详情 RK3588 核心板是一款由贝启科技自主研发的基于瑞芯微 RK3588 AI 芯片的智能核心…

word 常用功能记录

word手册 多行文字对齐标题调整文字间距打钩方框插入三线表插入参考文献自动生成目录 多行文字对齐 标题调整文字间距 打钩方框 插入三线表 插入一个最基本的表格把整个表格设置为无框线设置上框线【实线1.5磅】设置下框线【实线1.5磅】选中第一行&#xff0c;设置下框线【实线…

SpringBoot整合Elasticsearch报错

本文来记录一下SpringBoot整合Elasticsearch报错 文章目录 报错如下报错原因es7.15.2版本下载 报错如下 2024-01-02 15:09:10.349 ERROR 134936 --- [nio-8088-exec-6] o.a.c.c.C.[.[.[/]. [dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in c…

NGUI基础-图集制作(保姆级教程)

目录 图集是什么 如何打开图集制作工具 制作步骤 图集的三个关键配置 相关参数介绍 Atlas Material Texture Padding Tim Alpha PMA shader Unity Packer TrueColor Auto-upgrade Force Square Pre-processor 图集是什么 Unity图集&#xff08;Sprite Atlas&…

Rust基础语法判断语句读取命令行里边的数字使用match和if进行判断

use std::str::FromStr; use std::env;fn main() {// 新建一个let mut numbers Vec::new();for arg in env::args().skip(1){numbers.push(u64::from_str(&arg).expect("error parsing argument"));}if numbers.len() 0 || numbers.len() > 1 {eprint!(&quo…

IDEA2023 最新版详细图文安装教程(安装+运行测试+汉化+背景图设置)

IDEA2023 最新版详细图文安装教程 名人说&#xff1a;工欲善其事&#xff0c;必先利其器。——《论语》 作者&#xff1a;Code_流苏(CSDN) o(‐&#xff3e;▽&#xff3e;‐)o很高兴你打开了这篇博客&#xff0c;跟着教程去一步步尝试安装吧。 目录 IDEA2023 最新版详细图文安…

skynet 配置中lua服务创建流程

众所周知&#xff0c;skynet必须配置启动脚本&#xff0c;比如说如下配置 thread8 loggernil harbor0 start"main" lua_path"./skynet/lualib/?.lua;./skynet/lualib/?/init.lua;" luaservice"./skynet/service/?.lua;./app/?.lua;" lualoa…

linux挂载未分配的磁盘空间

目录 1.先查看是否有未分配的磁盘空间 2.分区 3.格式化新分区&#xff08;这里以ext4为例&#xff09; 4.创建一个目录用于挂载 5.将新分区挂载到目录 6.查看新的磁盘分区情况 7.配置系统在启动时自动挂载 1.先查看是否有未分配的磁盘空间 lsblk 可以看到/dev/vdb 是…

力扣_day1

两数之和 hash表的时间复杂度为什么是O(1)&#xff1f; hash表是基于数组链表的实现的。数组在内存中是一块连续的空间&#xff0c;只要知道查找数据的下标就可快速定位到数据的内存地址&#xff0c;即数组查找数据的时间复杂度为O(1)。 能用一次循环解决问题就用一次循环。…

面试经典150题(59-61)

leetcode 150道题 计划花两个月时候刷完&#xff0c;今天&#xff08;第二十九天&#xff09;完成了3道(59-61)150&#xff1a; 59.&#xff08;146. LRU 缓存&#xff09;题目描述&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUC…

EBU7140 Security and Authentication(三)密钥管理;IP 层安全

B3 密钥管理 密钥分类&#xff1a; 按时长&#xff1a; short term&#xff1a;短期密钥&#xff0c;用于一次加密。long term&#xff1a;长期密钥&#xff0c;用于加密或者授权。 按服务类型&#xff1a; Authentication keys&#xff1a;公钥长期&#xff0c;私钥短期…

算法训练第五十六天|583. 两个字符串的删除操作、72. 编辑距离

583. 两个字符串的删除操作&#xff1a; 题目链接 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 示例 : 输入: word1 "sea", word2 "eat" 输出: 2 解释: 第一…

python区别与C++的总结

数据类型 Python: 动态类型系统&#xff1a;类型在运行时自动检测&#xff0c;无需显式声明。内建类型&#xff1a;包括 int, float, str, bool, list, tuple, dict, set等。一切皆对象&#xff1a;所有数据类型都是对象&#xff0c;包括函数和类。没有原始数组&#xff1a;P…

Chocolatey

Chocolatey Software | PHP (Hypertext Preprocessor) 8.3.1 msi安装包https://github.com/chocolatey/choco/releases/download/2.2.2/chocolatey-2.2.2.0.msi 设置/安装 巧克力味Chocolatey CLI &#xff08;choco&#xff09;设置/安装 要求 受支持的 Windows 版本Windows …

webman插件创建

webman插件创建 介绍 应用插件实际上是一个完整的应用&#xff0c;它能以插件的形式安装到主项目中&#xff0c;使主项目快速获得某个模块功能。 例如&#xff1a;主项目需要一个问答系统&#xff0c;则可以安装一个问答应用插件&#xff0c;需要一个商城系统&#xff0c;则安…

Android14之audit2allow自动生成Selinux规则(一百七十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

Objects are not valid as a React child (found: object with keys {name}).

在jsx中可以嵌套表达式&#xff0c;将表达式作为内容的一部分&#xff0c;但是要注意&#xff0c;普通对象不能作为子元素&#xff1b;但是数组&#xff0c;react元素对象是可以的 如下&#xff1a;不能将stu这个对象作为子元素放 function App() {const myCal imgStyleconst…

信息网络协议基础_IP网络服务质量

文章目录 概述为什么要增加服务质量支持功能?如何表述服务质量?如何区分数据QoS网络服务等级协议综合服务原理区分服务原理PHB综合-区分服务概述 为什么要增加服务质量支持功能? 如何表述服务质量?

c语言:设计投票小程序|练习题

一、题目 设计一个投票小程序 如图&#xff1a; 二、代码图片【带注释】 三、源代码【带注释】 #include <stdio.h> #include<string.h> void win(int,int,int); int main() { char ch[5]; int countLili0; int countjp0; int countzx0; int …

mysql 单表 操作 最大条数验证 以及优化

1、背景 开车的多年老司机&#xff0c;是不是经常听到过&#xff0c;“mysql 单表最好不要超过 2000w”,“单表超过 2000w 就要考虑数据迁移了”&#xff0c;“你这个表数据都马上要到 2000w 了&#xff0c;难怪查询速度慢”。 2、实验 实验一把看看… 建一张表 CREATE TABL…