代码随想录笔记|C++数据结构与算法学习笔记-二叉树(七)|LeetCode617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

本文主要是介绍代码随想录笔记|C++数据结构与算法学习笔记-二叉树(七)|LeetCode617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 617.合并二叉树
    • 思路以及遍历顺序
    • 伪代码
    • CPP代码
  • 700.二叉搜索树中的搜索
    • 搜索树的特性
    • 伪代码
    • CPP代码
  • 98.验证二叉搜索树
    • 搜索树的特性
    • 直白想法
    • 代码误区
    • 伪代码
    • CPP代码
    • 双指针优化

617.合并二叉树

力扣题目链接

文章讲解:合并二叉树

视频讲解:一起操作两个二叉树?有点懵!| LeetCode:617.合并二叉树

思路以及遍历顺序

主要是考察一起操作两个二叉树的能力。

还是使用前序是最合理的,先合并根结点,再向左处理。比较符合逻辑。

伪代码

  • 确定递归函数的参数和返回值:首先要合入两个二叉树,那么参数至少是要传入两个二叉树的根节点,返回值就是合并之后二叉树的根节点。
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) 
  • 确定终止条件:因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2,如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。
if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2
if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1
  • 确定单层递归的逻辑:

单层递归的逻辑就比较好写了,这里我们重复利用一下t1这个树,t1就是合并之后树的根节点(就是修改了原来树的结构)。

那么单层递归中,就要把两棵树的元素加到一起。

t1->val += t2->val;	//中

接下来t1 的左子树是:合并 t1左子树 t2左子树之后的左子树。

t1 的右子树:是 合并 t1右子树 t2右子树之后的右子树。

最终t1就是合并之后的根节点。

t1->left = mergeTrees(t1->left, t2->left);	//左
t1->right = mergeTrees(t1->right, t2->right); //右
return t1;

CPP代码

//前序遍历
class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1// 修改了t1的数值和结构t1->val += t2->val;                             // 中t1->left = mergeTrees(t1->left, t2->left);      // 左t1->right = mergeTrees(t1->right, t2->right);   // 右return t1;}
};

对于中序、后序遍历改变顺序即可。

700.二叉搜索树中的搜索

力扣题目地址

文章讲解:700.二叉搜索树中的搜索

视频讲解:不愧是搜索树,这次搜索有方向了!| LeetCode:700.二叉搜索树中的搜索

搜索树的特性

二叉搜索树中,根结点比左子树结点都要大,比右子树结点都要小。同样,其左右子树也符合这个规则。

在二叉搜索树中,它自带顺序,所以也不关注其前中后序了。因为其结点的大小规则,已经为我们确定了搜索规则。

伪代码

  • 确定递归函数的参数和返回值:递归函数的参数传入的就是根节点和要搜索的数值,返回的就是以这个搜索数值所在的节点。
TreeNode* searchBST(TreeNode* root, int val)
  • 确定终止条件:如果root为空,或者找到这个数值了,就返回root节点。
if (root == NULL || root->val == val) return root;
  • 确定单层递归逻辑:因为二叉搜索树的结点是有序的,所以可以有方向得去搜索。

如果root->val > val,搜索左子树,如果root->root < val,就搜索右子树,如果最后都没有搜索到,就返回NULL

TreeNode* result = NULL;
if (root->val > val) result = searchBST(root->left, val);
if (root->val < val) result = searchBST(root->right, val);
return result;

CPP代码

class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {if (root == NULL || root->val == val) return root;TreeNode* result = NULL;if (root->val > val) result = searchBST(root->left, val);if (root->val < val) result = searchBST(root->right, val);return result;}
};
//or
class Solution {
public:TreeNode* searchBST(TreeNode* root, int val) {if (root == NULL || root->val == val) return root;if (root->val > val) return searchBST(root->left, val);if (root->val < val) return searchBST(root->right, val);return NULL;}
};

98.验证二叉搜索树

力扣题目链接

文章讲解:98.验证二叉搜索树

视频讲解:你对二叉搜索树了解的还不够! | LeetCode:98.验证二叉搜索树

其实本题的精髓就是抓住:二叉搜索树的中序遍历结果是严格从小到大的!

搜索树的特性

左子树里的结点元素都小于中结点,右子树的所有元素都大于中结点;同时左右子树均符合这样的规则。

所以根据此特性,如果我们中序遍历,那么这个元素就是有序的

直白想法

直接中序遍历二叉树,然后把所有元素都保存到一个数组上,然后判断这个数组是不是单调递增的就可以了。

  • 函数的返回值和参数、确定终止条件、单层递归逻辑
bool isvalid(TreeNode* root){if (root == NULL) return true;//啥二叉树都是空结点isvalid(root->left);	//中序遍历vec.push_back(root->val);isvalid(root->right);
}

然而!该方法并不是最有办法,因为我们额外定义了一个数组,然后把二叉树变成一个数组,然后判断数组是否有序。太麻烦了,我们可以直接在遍历过程中判断这个元素是不是单调递增的。

代码误区

经典错误:

if (root->val > root->left->val && root->val < root->right->val)return

上述代码逻辑就是,root的值大于左孩子的值并且root的值大于右孩子的值。

但这样就进入了一个误区,二叉搜索树是要求根结点比左子树的所有结点都要大,不仅仅是左孩子。

伪代码

先定义一个全局变量:用来比较遍历的节点是否有序,因为后台测试数据中有int最小值,所以定义为longlong的类型,初始化为longlong最小值。

long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值
  • 函数的返回值和参数:注意递归函数要有bool类型的返回值, 在二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?中讲了,只有寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值

    其实本题是同样的道理,我们在寻找一个不符合条件的节点,如果没有找到这个节点就遍历了整个树,如果找到不符合的节点了,立刻返回

bool isValidBST(TreeNode* root)
  • 确定终止条件:空结点也是二叉搜索树
if (root == NULL) return true;
  • 确定单层递归逻辑:中序遍历,一直更新maxVal,一旦发现maxVal >= root->val,就返回false,注意元素相同时候也要返回false
bool left = isValidBST(root->left);         // 左// 中序遍历,验证遍历的元素是不是从小到大
if (root->val > maxVal) maxVal = root->val; // 中
else return false;bool right = isValidBST(root->right);       // 右
return left && right;

CPP代码

class Solution {
public:long long maxVal = LONG_MIN; // 因为后台测试数据中有int最小值bool isValidBST(TreeNode* root) {if (root == NULL) return true;bool left = isValidBST(root->left);// 中序遍历,验证遍历的元素是不是从小到大if (maxVal < root->val) maxVal = root->val;else return false;bool right = isValidBST(root->right);return left && right;}
};

双指针优化

我们上面借助了一个中间值,其实还是不好,因为有可能搜索树的最小值比中间值还要小,那就不行了。

所以我们用双指针直接进行比较!

TreeNode* pre = NULL; //记录我们当前遍历的前一个结点,然后我们的root和pre进行比较//只用重写中间逻辑
if (pre != NULL && pre->val >= root->val)return false;
pre = root;
//从这个地方才开始,pre实现了记录root的前一个结点,在此之前pre总是为NULL

这篇关于代码随想录笔记|C++数据结构与算法学习笔记-二叉树(七)|LeetCode617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/871467

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意