【leetcode100-044到050】【二叉树】七题合集

昨天光写题忘写文章了,合并到今天一起写了///一共七个题///

【二叉搜索树中第k小元素】

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

思路:

搜索树!第一反应肯定是中序升序。方便起见我们先建立一个全局变量用来记录当前访问的节点是第几个,然后把中序遍历的板子糊上去就好啦。这题标mid我是不同意的,他真的不配。。。

class Solution {
public:int cnt=0;int kthSmallest(TreeNode* root, int k) {stack<TreeNode*> stk;while(root!=nullptr||!stk.empty()){while(root!=nullptr){stk.push(root);root=root->left;}root =stk.top();stk.pop();if(++cnt==k)break;root=root->right;}return root->val;}
};

【二叉树右视图】

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

思路:

  • 第一种,带计数的层序遍历,把每一层的最后一个节点放进答案里面就好了。
  • 第二种,变形的先序遍历,根左右改成根右左+记录当前层数,这样可以保证第一次遍历到某层的节点的时候访问的必定是当前层最右侧的节点。(懒得实现了。。)
class Solution {
public:vector<int> rightSideView(TreeNode* root) {vector<int> ans;queue<TreeNode*> q;if (root)q.push(root);while (!q.empty()) {int cnt = q.size();TreeNode* cur = nullptr;while (cnt) {cur = q.front();q.pop();if (cur->left)q.push(cur->left);if (cur->right)q.push(cur->right);if (cnt-- == 1)ans.push_back(cur->val);}}return ans;}
};

【二叉树展开为链表】

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

思路:

  • 第一种,拆树。对任意节点,如果没有左子树,显然已经符合要求,如果有的话把左子树拆下来放右子树,那右子树怎么办呢?显然,右子树会在左子树全部遍历完以后才被遍历,所以我们暂时把它接到左子树最右下角的节点右边,等着后面再去处理。如此一路向右下行,拆完所有节点的时候就完成了。
  • 第二种,既然要的是先序遍历顺序的链表,那我们先序遍历一遍,然后把每个当前节点都拆下来重装一遍行不行?答案是不行......按照先序拆下来的话,处理完根节点,孩子都找不到了,还怎么遍历......但是!我们可以倒着来啊,如果我们对每一个节点,都先处理完它的孩子再处理它自己,那么孩子节点丢了就丢了呗,反正再也用不着了啊。于是,我们建立一个pre指针,指向当前节点之前,最后被处理的那个节点,并把当前节点接在pre的前面,然后成为新的pre,就解决问题啦。当然,因为是倒着接的,所以遍历顺序得改成“右左根”这样,递归嘛改顺序太简单了,换一下代码顺序就好啦。
class Solution {
public:void flatten(TreeNode* root) {while(root){if(root->left!=nullptr) {TreeNode* R=root->left;while(R->right) R=R->right;R->right=root->right;root->right=root->left;root->left=nullptr;}root=root->right;}return;}
};
class Solution {
public:TreeNode* pre= nullptr;void flatten(TreeNode* root) {
//先序遍历倒序:右左根if(root==nullptr)return;flatten(root->right);flatten(root->left);root->right=pre;root->left=nullptr;pre=root;}
};

【从前序与中序遍历序列构造二叉树】

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

思路:

这题虽然写了双解,但栈迭代那个我只能说我看懂了会写代码了...要我写题解思路实在是做不到,就写一下递归的思路算了qaq。

其实这个构造二叉树的过程用自然语言描述非常简单,我们最后做的不过是用代码翻译了这个过程:用前序找到当前的根节点,在中序找到根节点的位置,此时我们知道了左右子树各自的节点数量,which means我们知道了前序和中序序列中哪一段属于左子树,哪一段属于右子树,此时已经可以递归,算好参数传一下就搞定啦。(不过这个参数看起来真的蛮恶心的)

class Solution {
public:TreeNode* helper(vector<int>& preorder, vector<int>& inorder, int l1,int r1, int l2, int r2) {//区间不合法退出递归if (l1 > r1 || l2 > r2)return nullptr;//取先序首位int curVal = preorder[l1];//在中序找到int i = l2;for (; i <= r2; i++) {if (inorder[i] == curVal)break;}//构建根节点TreeNode* root = new TreeNode(curVal);//确定左子树节点数,更新左子树区间,递归构建root->left = helper(preorder, inorder, l1 + 1, i + l1 - l2, l2, i - 1);//右子树同理root->right = helper(preorder, inorder, i + l1 - l2 + 1, r1, i + 1, r2);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int s1 = preorder.size();int s2 = inorder.size();return helper(preorder, inorder, 0, s1 - 1, 0, s2 - 1);}
};

【路径总和】

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

思路:

这题也写了双解,从两个解都获得了一点思路的突破,可开心了。

  • 双递归:对任意节点来说,从它出发的满足要求的路径数量=往左子树走时的满足路径数量+往右子树走时的满足路径数量+不走时满足路径数量。而左右子树的满足路径数量又可以用同样的方式获得,于是第一个递归建立了,它返回了每个节点作为起点时可以提供的路径数量。然后,我们建立第二个递归,去遍历所有节点并加和它们提供的路径数量,最后返回总数。
  • 前缀和:为了优化双递归中大量重复的计算,我们试着来建立一个表记录根节点到当前节点的路径和。然后就可以用“子数组和”的思想在树的遍历过程中记录满足数量啦,虽然底层逻辑是一样的,但是把这个方法应用到树上的时候有一个很重要的不同点!数组的遍历只会从前往后走,可是树的遍历是有倒退过程的诶,所以当我们用完某个节点并退出这颗子树的时候,必须要把当前节点提供的路径和从表中删去,因为剩余还未遍历的路径都不可能再经过这个节点啦,那么即使它提供的前缀和在“数值”上满足了题目的要求,实际上相应的路径确是不存在的!
class Solution {
public:int cal(TreeNode* root, long long target) {if (root == nullptr)return 0;return cal(root->left,target-root->val)+cal(root->right,target-root->val)+(root->val==target);}int pathSum(TreeNode* root, long long targetSum) {if (root == nullptr)return 0;int ans = 0;ans += cal(root, targetSum);ans += pathSum(root->left, targetSum);ans += pathSum(root->right, targetSum);return ans;}
};
class Solution {
private:unordered_map<long long, int> prefixMap;long long target;public:int pathSum(TreeNode* root, long long targetSum) {prefixMap.clear();target = targetSum;prefixMap[0] = 1;return recur(root, 0);}private:int recur(TreeNode* node, long long curSum) {if (node == nullptr) {return 0;}int res = 0;curSum += node->val;res += prefixMap[curSum - target];prefixMap[curSum]++;res += recur(node->left, curSum);res += recur(node->right, curSum);prefixMap[curSum]--;return res;}
};

【二叉树最近公共祖先】

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

思路:

嗯这题我自己先造了一个小屎山qaq,虽然很屎,但自己写并一次性AC的快乐还是让我决定给这坨答辩留下一点记录。

  • 屎山版:用一个表按照中序遍历序列把每个节点出现的次序记下来,然后从根节点开始判断当前节点与p和q的位置关系,走到p自身,或q自身,或第一个使得p和q在自身两边的节点时,找到答案。
  • 消息传递版:对任意节点,检查它是否为p或q,并从叶子节点开始向上传递消息。首先,空节点肯定报告nullptr;其次,自己是p或q时,向上报告自身信息。以上两种情况在访问某节点时立刻就可以完成判断,而都不满足时(不是p不是q不是空节点),进入以下三种情况,需要根据左右孩子传上来的信息才能判断。第一种,左右孩子均报告无效信息,那么继续向上报告无效信息nullptr;第二种,左右孩子均报告了有效信息时,找到答案啦!第三种,左右孩子中有且只有一个报告了有效信息,把该信息继续向上传递。
class Solution {
public:int index = 0;unordered_map<TreeNode*, int> idx;void dfs(TreeNode* root) {if (root == nullptr)return;dfs(root->left);idx.emplace(root, index++);dfs(root->right);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//建立中序哈希表dfs(root);int RIndex = idx[root];int PIndex = idx[p];int QIndex = idx[q];//当p和q还在当前节点的同一侧时,继续循环while ((PIndex < RIndex && QIndex < RIndex) ||(PIndex > RIndex && QIndex > RIndex)) {if (PIndex < RIndex && QIndex < RIndex) {root = root->left;RIndex = idx[root];}if (PIndex > RIndex && QIndex > RIndex) {root = root->right;RIndex = idx[root];}}return root;}
};
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(root==nullptr)return nullptr;if(root==p||root==q)return root;TreeNode* left=lowestCommonAncestor(root->left,p,q);TreeNode* right=lowestCommonAncestor(root->right,p,q);if(left==nullptr&&right==nullptr)return nullptr;if(left&&right)return root;return left? left:right;}
};

【二叉树最大路径和】

二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

思路:

又是一个拓宽思路而且可以复用的题。由于本题在每个节点得到的计算结果(可能会向左右两边延伸的最大路径和)和每个节点需要传给上层函数的结果(至多向一边延伸的最大路径和)是不一样的,苯人想破头了甚至开始试图传pair给上层...套了三层函数终于解决了以后,官解告诉我,你在每个节点把要算的给算了,用个全局变量记一下,然后只把需要传递的传上去不就好了吗?啊,可恶,这样真的显得我很傻逼。

  • 总之还是dfs框架;
  • 空节点向上传0;
  • 非空节点先计算以自己为顶点时可以获得的最好结果curSum,但!这个结果是不上传的,它只用来更新全局变量maxInsideSum;
  • 非空节点继续计算需要上传的结果:max(自己,自己+左子树传上来的,自己+右子树传上来的),如果大于0就上传,如果最好结果都小于0,意味着进入本子树对路径和没有任何正面贡献,别进来了,传个0回去吧;
  • 走完整棵树,全局变量里记录的就是我们想要的最优解。
class Solution {
public:int maxInsideSum = INT_MIN;int dfs(TreeNode* root) {if (root == nullptr)return 0;int L = dfs(root->left);int R = dfs(root->right);int curSum = L + R + root->val;maxInsideSum = max(curSum, maxInsideSum);int temp = max(L, R) + root->val;return temp > 0 ? temp : 0;}int maxPathSum(TreeNode* root) {dfs(root);return maxInsideSum;}
};

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

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

相关文章

java SSM政府采购管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM政府采购管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

飞书+ChatGPT+cpolar搭建企业智能AI助手并实现无公网ip远程访问

文章目录 推荐 前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂…

C语言第五弹---分支语句(上)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 分支语句 1、if语句1.1、if1.2、 else1.3、 分支中包含多条语句1.4、嵌套if1.5、 悬空else问题 2、关系操作符3、 条件操作符总结 C语言是结构化的程序设计语言&…

第04章_IDEA的安装与使用(下)(IDEA断点调试,IDEA常用插件)

文章目录 第04章_IDEA的安装与使用&#xff08;下&#xff09;8. 快捷键的使用8.1 常用快捷键8.2 查看快捷键1、已知快捷键操作名&#xff0c;未知快捷键2、已知快捷键&#xff0c;不知道对应的操作名 8.3 自定义快捷键8.4 使用其它平台快捷键 9. IDEA断点调试(Debug)9.1 为什么…

如何设计WIndows系统下的单例进程程序?

1. 如何设计WIndows系统下的单例进程程序&#xff1f; 为了设计一个Windows系统下的单例进程程序&#xff0c;你可以遵循以下步骤&#xff1a; 首先&#xff0c;确定你的应用程序只能运行一个实例。这可以通过使用互斥量&#xff08;Mutex&#xff09;来实现。互斥量是一种同…

一零七七、将Hexo cl Hexo g Hexo s通过systemctl命令管理

背景&#xff1a; 服务器需要执行hexo s来运行项目&#xff0c;但这个命令是基于前台的&#xff0c;故想直接嫁接在systemctl命令基础上来控制环境&#xff1a; Centos 8 前置环境就不说了,Hexo安装好&#xff0c;起码装完自己得先看hexo命令生效没&#xff0c;前置环境做好后…

Leetcode刷题笔记题解(C++):LCR 102. 目标和

思路&#xff1a;利用回溯去遍历&#xff0c;回溯结束条件为遍历到最后一个数字&#xff0c;如果符合target则目标数1 class Solution { public://记录合为结果的数量int count 0;int findTargetSumWays(vector<int>& nums, int target) {//利用回溯来寻找backtrac…

v-if 和 v-show 有什么区别?

v-if 和 v-show 有什么区别&#xff1f; v-if 是“真正”的条件渲染&#xff0c;因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建&#xff0c; 操作的实际上是 dom 元素的创建或销毁。 v-show 就简单得多——不管初始条件是什么&#xff0c;元素总是…

《WebKit 技术内幕》之九(2): JavaScript引擎

2 V8引擎 2.1 基础 V8是一个开源项目&#xff0c;也是一个JavaScript引擎的实现。它最开始是由一些语言方面的专家设计出来的&#xff0c;后被Google收购&#xff0c;成为了JavaScript引擎和众多相关技术的引领者。其目的很简单&#xff0c;就是为了提高性能。因为在当时之前…

#vue3 实现前端下载excel文件模板功能

一、需求&#xff1a; 前端无需通过后端接口&#xff0c;即可实现模板下载功能。 通过构造一个 JSON 对象&#xff0c;使用前端常用的第三方库 xlsx&#xff0c;可以直接将该 JSON 对象转换成 Excel 文件&#xff0c;让用户下载模板 二、效果&#xff1a; 三、源码如下&…

图像处理工具包Pillow的使用分享

Pillow 是 Python 中一个流行的图像处理库&#xff0c;它是 PIL&#xff08;Python Imaging Library&#xff09;的一个友好的分支版本。Pillow 提供了许多功能&#xff0c;使得图像处理变得容易和方便。下面是一些基本用法和示例&#xff1a; 安装 Pillow 首先&#xff0c;你…

MES智能制造系统,定制智造工厂的“大脑”,提升生产力智慧之选

制造执行系统&#xff08;MES&#xff09;是专为制造企业设计的执行管理软件&#xff0c;用于管理整个工厂的生产过程。随着智能制造的推动&#xff0c;信息技术水平的提升对于实现智能工厂至关重要在数字化技术不断进步和发展的背景下&#xff0c;MES系统作为面向制造企业车间…

【JavaEE进阶】 Spring Boot⽇志

文章目录 &#x1f38b;关于日志&#x1f6a9;为什么要学习⽇志&#x1f6a9;⽇志的⽤途&#x1f6a9;日志的简单使用 &#x1f384;打印⽇志&#x1f6a9;程序中得到⽇志对象&#x1f6a9;使⽤⽇志对象打印⽇志 &#x1f38d;⽇志格式的说明&#x1f6a9;⽇志级别的作用&#…

实时asr新服务串讲

1.背景及现状 工程方面目前语音相关服务存在大量重复代码&#xff0c;逻辑复杂&#xff0c;文档缺失&#xff0c;并且某些细节设计不合理。基于目前现状&#xff0c;代码业务与功能耦合严重&#xff0c;迭代困难&#xff0c;将来增加新的能力也需要改动音频数据相关代码&#x…

【SpringBoot3】Spring Boot 3.0 集成 Mybatis Plus

文章目录 一、什么是 Mybatis Plus特性 二、Spring Boot 3.0 集成 Mybatis Plus三、Mybatis Plus 查询示例1、普通查询2、分页查询 参考 一、什么是 Mybatis Plus MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增…

Allegro如何导入芯片的Pin Delay?

Allegro在做等长时,需要导入芯片的Pin Delay才能做真正的等长。因为有些芯片内部的引脚本身就是不等长的,例如海思的部分芯片。 那么如何导入芯片的Pin Delay呢? 1、打开约束管理器,点击Properties(属性)→Component(器件)→Pin Properties→General。 在右栏找到芯片U1,…

实时嵌入式Linux设备基准测试快速入门4测试和测量

本章将介绍主要测试方案及其具体配置和结果。在介绍实际测量结果之前&#xff0c;将尽可能总结被测设备的特性。最后&#xff0c;将对结果进行分析&#xff0c;并概述由于高速缓存一致性问题造成的延迟方面的主要瓶颈&#xff0c;提出减少延迟的解决方案&#xff0c;并解释用于…

JavaSE核心基础-一维数组-笔记

1.数组概念 相同类型数据的集合&#xff0c;它在内存空间的存储是连续的。数组其实也是一个容器,用来存储固定个数相同类型的数据&#xff0c;数组中存储的数据叫做元素。 2.数组定义 方式1&#xff1a; 数据类型[] 数组名 new 数据类型[数组长度]; 数据类型 数组…

Duplicate object key json(520)

亲爱的码友&#xff0c;当你看到这个错误 请查看一下你的json文件内容的关键词是不是重复了 举个栗子&#x1f330; 往下翻翻&#xff1a; 删一个就行&#xff01;&#xff01;&#xff01; 被自己傻哭了吧&#x1f923;&#x1f923;&#x1f923;

js实现九九乘法表

效果图 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script type"text/javascript">// 输出乘法口诀表// document.write () 空格 " " 换行…