Leetcode算法训练日记 | day20

一、合并二叉树

1.题目

Leetcode:第 617 题

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

示例 1:

输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

示例 2:

输入:root1 = [1], root2 = [1,2]
输出:[2,2]

2.解题思路

首先检查两个输入树的根节点是否为空,如果其中一个为空,则返回另一个作为结果。如果两个根节点都不为空,将合并它们的值,并对它们的左右子树递归地执行合并操作。这个过程一直持续到所有节点都被合并,最终返回更新后的根节点,包含了合并后二叉树的根。

3.实现代码

#include <iostream>
#include <vector>
#include <queue>
using namespace std;// 定义一个结构体TreeNode,用于表示二叉树的节点。
struct TreeNode {int val; // 存储节点的值。TreeNode* left; // 指向该节点左子树的指针。TreeNode* right; // 指向该节点右子树的指针。// TreeNode的构造函数,用于创建一个TreeNode实例。// 参数x是节点的值,left和right默认为NULL,表示没有左右子节点。TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};// 一、合并两棵二叉树(递归法)。
class Solution1 {
public:// mergeTrees函数用于合并两个给定的二叉树root1和root2。TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if (root1 == NULL) return root2;// 如果root1为空,则返回root2作为合并后的树的根节点。if (root2 == NULL) return root1; // 如果root2为空,则返回root1作为合并后的树的根节点。root1->val = root1->val + root2->val;// 将root1的值与root2的值相加,并将结果赋给root1,这是合并操作的一部分。root1->left = mergeTrees(root1->left, root2->left);// 递归调用mergeTrees函数合并root1和root2的左子树。root1->right = mergeTrees(root1->right, root2->right); // 递归调用mergeTrees函数合并root1和root2的右子树。return root1;// 返回更新后的root1作为合并后的树的根节点。}
};// 二、合并两棵二叉树(迭代法法)。
class Solution2 {
public:// mergeTrees函数用于合并两个给定的二叉树root1和root2。TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {if (root1 == NULL) return root2;  // 如果root1为空,直接返回root2作为合并后的树的根节点。if (root2 == NULL) return root1; // 如果root2为空,直接返回root1作为合并后的树的根节点。queue<TreeNode*> que; // 创建一个队列que,用于在合并过程中存储待处理的节点对。que.push(root1); // 将root1和root2入队。que.push(root2);// 使用while循环处理队列中的所有节点对。while (!que.empty()) {// 取出队列中的两个节点,node1对应root1的节点,node2对应root2的节点。TreeNode* node1 = que.front();que.pop();TreeNode* node2 = que.front();que.pop();node1->val = node1->val + node2->val;// 将node1和node2的值相加,并将结果赋给node1。// 如果node1和node2都有左子节点,将它们入队以进行后续合并。if (node1->left != NULL && node2->left != NULL) {que.push(node1->left);que.push(node2->left);}// 如果node1和node2都有右子节点,将它们入队以进行后续合并。if (node1->right != NULL && node2->right != NULL) {que.push(node1->right);que.push(node2->right);}//因为返回的是root1二叉树,只需考虑考虑root1存在空节点对应的root2不为空节点的情况// 而不需要考虑root1存在节点对应的root2为空节点的情况// 如果node1没有左子节点,但node2有左子节点,将node2的左子节点赋给node1。if (node1->left == NULL && node2->left != NULL) {node1->left = node2->left;}// 如果node1没有右子节点,但node2有右子节点,将node2的右子节点赋给node1。if (node1->right == NULL && node2->right != NULL) {node1->right = node2->right;}//因为返回的是root1二叉树,所以不需要考虑root1存在节点对应的root2为空节点的情况}return root1;// 由于函数只接收root1的指针,返回root1,此时它已经是合并后的树的根节点。}
};

二、二叉搜索树中的搜索

1.题目

Leetcode:第 700 题

给定二叉搜索树(BST)的根节点 root 和一个整数值 val

你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。

示例 1:

输入:root = [4,2,7,1,3], val = 2
输出:[2,1,3]

示例 2:

输入:root = [4,2,7,1,3], val = 5
输出:[]
2.解题思路

首先检查当前根节点是否为空或者是否已经找到目标值。如果当前节点为空,或者其值等于目标值,则直接返回当前节点。如果当前节点的值大于目标值,函数递归地在左子树中查找;如果当前节点的值小于目标值,则递归地在右子树中查找。最终,函数返回查找结果,如果找到了匹配的节点,则返回该节点;否则返回NULL。

3.实现代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;// 定义一个结构体TreeNode,用于表示二叉树的节点。
struct TreeNode {int val; // 存储节点的值。TreeNode* left; // 指向该节点左子树的指针。TreeNode* right; // 指向该节点右子树的指针。// TreeNode的构造函数,用于创建一个TreeNode实例。// 参数x是节点的值,left和right默认为NULL,表示没有左右子节点。TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};// 一、在二叉搜索树中查找特定值的节点(递归法)。
class Solution1 {
public:// searchBST函数用于在二叉搜索树root中查找值为val的节点。TreeNode* searchBST(TreeNode* root, int val) {if (root == NULL || root->val == val) return root; // 如果根节点为空,或者根节点的值等于要查找的值val,返回当前节点。TreeNode* result = NULL;// 初始化结果指针为NULL,用于存储找到的节点。if (root->val > val) result = searchBST(root->left, val);// 如果根节点的值大于要查找的值val,递归搜索左子树。if (root->val < val) result = searchBST(root->right, val);// 如果根节点的值小于要查找的值val,递归搜索右子树。   return result;// 返回搜索结果,如果找到则返回找到的节点,否则返回NULL。}
};// 二、在二叉搜索树中查找特定值的节点(递归法)。
class Solution2 {
public:// searchBST函数用于在二叉搜索树root中查找值为val的节点并返回。TreeNode* searchBST(TreeNode* root, int val) {while (root != NULL) {  // 使用while循环,当root不为NULL时继续搜索。if (root->val > val) {// 如果root的值大于要查找的值val,向左子树搜索。root = root->left;}else if (root->val < val) {// 如果root的值小于要查找的值val,向右子树搜索。root = root->right;}else {// 如果root的值等于要查找的值val,找到了目标节点,返回root。return root;}}return NULL; //未找到就返回NULL。}
};

三、验证二叉搜索树

1.题目

Leetcode:第 98 题

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

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

  • 节点的左

    子树

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

示例 1:

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

示例 2:

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

1.一般递归法:递归遍历整个二叉树,将所有节点的元素使用vector保存,检查是否所有的元素都是严格递增的,如果不是,就说明不是一个有效的二叉搜索树。

2.双指针递归法:在递归遍历整个二叉树的过程中,用两个指针来检查是否满足每个节点的值都应该大于其左子树中所有节点的值,并且小于其右子树中所有节点的值。如果不是,就说明不是一个有效的二叉搜索树。

3.迭代法:通过使用栈 st 来存储待访问的节点,可以在每次循环中选择最左边的节点进行访问,从而模拟中序遍历的过程。同时,使用指针 pre 来记录遍历过程中的前一个节点值,以便在访问当前节点时检查其是否违反了二叉搜索树的性质。如果遍历完整棵树都没有发现违反性质的情况,则可以认为该二叉树是有效的二叉搜索树。

3.实现代码
#include <iostream>
#include <vector>
#include <stack>
using namespace std;// 定义一个结构体TreeNode,用于表示二叉树的节点。
struct TreeNode {int val; // 存储节点的值。TreeNode* left; // 指向该节点左子树的指针。TreeNode* right; // 指向该节点右子树的指针。// TreeNode的构造函数,用于创建一个TreeNode实例。// 参数x是节点的值,left和right默认为NULL,表示没有左右子节点。TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};// 一、验证二叉搜索树(一般递归法)。
class Solution {
public:vector<int> vec; // 定义一个vec,用于存储二叉树节点的值// 定义一个名为traversal的成员函数,用于执行二叉树的中序遍历。void traversal(TreeNode* root) {if (root == NULL) return; // 如果当前节点为空,直接返回,不执行任何操作。traversal(root->left); // 递归调用traversal函数遍历当前节点的左子树。vec.push_back(root->val); // 访问当前节点,将其值添加到vec中。traversal(root->right); // 递归调用traversal函数遍历当前节点的右子树。}// 定义一个名为isValidBST的成员函数,用于验证给定的二叉树是否为有效的二叉搜索树。// 参数root是二叉树的根节点指针。bool isValidBST(TreeNode* root) {vec.clear(); // 清空向量vec,为新的中序遍历做准备。traversal(root); // 调用traversal函数,传入根节点,执行中序遍历。for (int i = 1; i < vec.size(); i++) {// 遍历向量vec,检查中序遍历的结果是否为升序。if (vec[i] <= vec[i - 1]) return false; // 如果发现任何违反升序的元素对,返回false。}return true; // 如果遍历完成没有发现违反升序的元素对,返回true,表明是有效的二叉搜索树。}
};//二、验证二叉搜索树(双指针递归法)。
class Solution2 {
public:// 定义一个指向TreeNode的指针pre,初始化为NULL,用于在遍历过程中记录前一个访问的节点。TreeNode* pre = NULL;// 定义一个名为isValidBST的成员函数,用于验证给定的二叉树是否为有效的二叉搜索树。// 参数root是二叉树的根节点指针。bool isValidBST(TreeNode* root) {if (root == NULL) return true;  // 如果当前节点为空,说明是有效的二叉搜索树,返回true。// 递归调用isValidBST函数检查当前节点的左子树是否为有效的二叉搜索树。bool left = isValidBST(root->left);// 如果pre不为NULL,并且前一个访问的节点的值大于当前节点的值,说明不是有效的二叉搜索树,返回false。// 这是二叉搜索树的性质:每个节点的值都应该大于其左子树中所有节点的值。if (pre != NULL && pre->val > root->val) return false;pre = root; // 更新pre为当前节点,以便在递归检查右子树时使用。// 递归调用isValidBST函数检查当前节点的右子树是否为有效的二叉搜索树。bool right = isValidBST(root->right);// 返回左子树和右子树的检查结果,只有当左右子树都满足二叉搜索树的性质时,整个树才是有效的。return left && right;}
};// 三、验证二叉搜索树(迭代法)。
class Solution3 {
public:// 定义一个成员函数isValidBST,用于验证给定的二叉树是否为有效的二叉搜索树。// 参数root是二叉树的根节点指针。bool isValidBST(TreeNode* root) {stack<TreeNode*> st; // 定义一个栈st,用于存放二叉树的节点指针,辅助进行迭代遍历。TreeNode* cur = root; // 定义一个当前节点指针cur,初始指向根节点。TreeNode* pre = NULL; // 定义一个前一个节点指针pre,初始为NULL,用于记录遍历过程中的前一个节点值。// 当当前节点不为空,或者栈st不为空时,继续遍历。while (cur != NULL || !st.empty()) {if (cur != NULL) {// 如果当前节点不为空,将当前节点压入栈st,并将cur更新为当前节点的左子节点。st.push(cur); // 将当前节点压入栈中。cur = cur->left; // 将cur更新为当前节点的左子节点,开始遍历左子树。}else {// 如果当前节点为空,从栈st中弹出一个节点作为当前节点。cur = st.top(); // 获取栈顶节点。st.pop(); // 弹出栈顶节点。// 如果pre不为空,并且当前节点的值小于pre记录的前一个节点的值,说明不是有效的二叉搜索树,返回false。// 这是二叉搜索树的性质:每个节点的值都应该大于其左子树中所有节点的值。if (pre != NULL && cur->val <= pre->val) {return false;}pre = cur;// 更新pre为当前节点。cur = cur->right;// 将cur更新为当前节点的右子节点,准备遍历右子树。}}// 如果遍历完整棵树都没有发现违反二叉搜索树性质的情况,则返回true,表明是有效的二叉搜索树。return true;}
};

ps:以上皆是本人在探索算法旅途中的浅薄见解,诚挚地希望得到各位的宝贵意见与悉心指导,若有不足或谬误之处,还请多多指教。

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

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

相关文章

基于SSM的电影网站(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的电影网站&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringMv…

196算法之谜在 JSP 中使用内置对象 request 获取 form 表单的文本框 text 提交的数据。

(1&#xff09;编写 inputNumber . jsp &#xff0c;该页面提供一个 form 表单&#xff0c;该 form 表单提供一个文本框 text &#xff0c;用于用户输入一个正整数&#xff0c;用户在 form 表单中输入的数字&#xff0c;单击 submit 提交键将正整数提交给 huiwenNumber . jsp 页…

开源项目ChatGPT-Next-Web的容器化部署(四)-- k8s容器部署使用configmap配置

一、接着上文 本文的内容是在k8s容器中&#xff0c;如何使用configmap对.env文件进行挂载&#xff0c;实现环境的差异化配置。 二、源码结构 项目ChatGPT-Next-Web使用了.env文件来配置不同环境下的值&#xff1a; 所以&#xff0c;我们同理新增两个配置文件&#xff0c;见下…

windows上使用influx2.7学习

参考 官方文档&#xff1a;https://docs.influxdata.com/influxdb/v2/ 下载 需要下载两样东西&#xff1a;influxd.exe和influx.exe influxd:influx数据库的服务端。下载地址&#xff1a;https://dl.influxdata.com/influxdb/releases/influxdb2-2.7.5-windows.zipinflux:连…

Linux 计算机网络

目录 一、网络协议 1、 "协议" 是一种约定 2、协议分层 二、网络模型 1、OSI七层模型 2、TCP/IP五层(或四层)模型 三、网络传输基本流程 四、数据包封装和分用 五、网络中的地址管理 六、网络编程套接字 1、理解源IP地址和目的IP地址 2、端口号 理解 &q…

Prototype 原型

意图 用原型实例指定创建对象的种类&#xff0c;并且通过复制这些原型创建新的对象。 结构 Prototype声明一个复制自身的接口。ConcretePrototype实现一个复制自身的操作。Client让一个原型复制自身从而创建一个新的对象。 适用性 当一个系统应该独立于他的产品创建、构成和…

第四百五十三回

文章目录 1. 问题描述2. 优化方法2.1 缩小范围2.2 替代方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取AppBar的高度"相关的内容&#xff0c;本章回中将介绍关于MediaQuery的优化.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 问题描述 我们在…

微信小程序uniapp+vue电力巡线任务故障报修管理系统2q91t

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 前端开发:vue 语言&#xff1a;javapythonnodejsphp均支持 运行软件:idea/eclipse/vscode/pycharm/wamp均支持 框架支持:Ssm/django/flask/t…

《看漫画学C++》第12章 可大可小的“容器”——向量

在C编程的世界里&#xff0c;数组是一种基础且广泛使用的数据结构。然而&#xff0c;传统的静态数组在大小固定、管理不便等方面的局限性&#xff0c;常常让开发者感到束手束脚。幸运的是&#xff0c;C标准库中的vector类为我们提供了一种更加灵活、高效的动态数组解决方案。 …

Socks5代理IP使用教程

当我们在互联网上浏览网页、下载文件或者进行在线活动时&#xff0c;隐私和安全问题常常被提及。在这样的环境下&#xff0c;一个有效的解决方案是使用Sock5IP。本教程将向您介绍Sock5IP的使用方法&#xff0c;帮助您保护个人隐私并提升网络安全。 一、什么是Sock5IP&#xff1…

4月9号总结

java学习 一.steam流 1.介绍 Stream 是 Java 8 中引入的一种处理集合数据的新抽象。它提供了一种高效且便利的方式来处理集合中的元素&#xff0c;支持函数式编程的特性&#xff0c;使得集合操作变得更加简洁和灵活。 2.创建 List和Set可以直接调用接口的steam方法转换为流 …

互联网大厂ssp面经(操作系统:part1)

1. 什么是进程和线程&#xff1f;它们之间有什么区别&#xff1f; a. 进程是操作系统中运行的一个程序实例。它拥有独立的地址空间和资源&#xff0c;可以独立执行。 b. 线程是进程内的一个执行单元&#xff0c;一个进程可以包含多个线程。 c. 线程共享进程的资源&#xff0c;…

Unity之PlayableGraph实现动画的正播和倒播

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之PlayableGraph实现动画的正播和倒播 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&am…

3d模型有边界框怎么去除---模大狮模型网

在3D建模软件中&#xff0c;边界框通常是用来表示模型的边界和外轮廓的&#xff0c;但有时候在渲染或导出模型时可能不希望显示这些边界框。以下是一些去除3D模型边界框的方法&#xff1a; 隐藏边界框选项&#xff1a; 在大多数3D建模软件中&#xff0c;边界框的显示可以通过简…

【从浅学到熟知Linux】冯诺依曼体系结构及进程概念详谈!

&#x1f3e0;关于专栏&#xff1a;Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 冯诺依曼体系结构操作系统如何理解管理操作系统概念设计操作系统目的系统调用和库函数概念 进程基本概念描…

移位寄存器

移位寄存器是如何工作的&#xff1f; 移位寄存器按照移位方向可分为左移位寄存器、右移位寄存器、双向移位寄存器。图11-15所示为用D触发器构成的4位左移位寄存器。待存数码由触发器F0的输入端D0输入&#xff0c;在移位脉冲作用下&#xff0c;可将数码从高位到低位向左逐步移入…

基于springboot+vue实现的艺术水平考级报名管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

信息收集笔记

1 简介 渗透的本质是信息收集 信息收集也叫做资产收集 信息收集是渗透测试的前期主要工作&#xff0c;是非常重要的环节&#xff0c;收集足够多的信息才能方便接下来的测试&#xff0c;信息收集主要是收集网站的域名信息、子域名信息、目标网站信息、目标网站真实IP、敏感/目…

2024.4.8Morris中序遍历(线索二叉树)学习

这次博主在学习完知识点和代码之后&#xff0c;准备对这个知识重新进行整理总结。站在一个初学者的角度来看待这个知识点&#xff0c;在他人的讲解基础上加一点点自己的理解&#xff0c;并记录下来。以加深自己的理解&#xff0c;并且希望能够帮助到你。博主是一个初学者&#…

HeidiSQL下载安装使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…