java算法day11
- 二叉树的递归遍历
- 二叉树的非递归遍历写法
- 层序遍历
递归怎么写?
按照三要素可以保证写出正确的递归算法:
1.确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
2.确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
3.确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
前置必会
一定要会自己写出树的类定义
public class TreeNode{TreeNode left;TreeNode right;int val;TreeNode(){}TreeNode(int val){this.val = val}TreeNode(int val,TreeNode right,TreeNode left){this.val = val;this.left = left;this.right = right;
}
144.二叉树的前序遍历
递归写法
class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();dfs(root,result);return result;}void dfs(TreeNode root,List<Integer> result){if(root==null){return;}result.add(root.val);dfs(root.left,result);dfs(root.right,result);}}
非递归写法:
我认为就是记思路。
1.用一个栈作为辅助。
2.前序遍历是根左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。之所以是反过来是因为,这样出栈的时候才是根左右的顺序。直接来看图模拟
即每次在处理根节点的时候,将根节点出队,然后将其右孩子先进栈,再将左孩子进栈。
这样进行处理之后,出栈的结果就会是前序遍历的结果。
如果还是不懂,我建议直接结合代码,然后结合上面图,记下来这个做法。我觉得这个直接想是不好想的。
非递归其实就是用辅助数据结构,配合循环
class Solution {public List<Integer> preorderTraversal(TreeNode root) {//结果集List<Integer> result = new ArrayList<>();//特判if(root == null){return result;}//创建辅助栈Deque<TreeNode> st = new ArrayDeque<>();//根节点先入栈st.push(root);//当栈不空的时候while(!st.isEmpty()){//先处理根节点,即将根节点出栈。这就对应着根TreeNode node = st.pop();//将出栈的根节点加入结果集result.add(node.val);//先将右节点加入栈中,可以这么想,早点加入,那么就晚点出。所以右节点出的时候,要比左节点晚,那么这里出也就是和上面节点出栈一个道理。所以这里就完成了根左右里面的根左。因为左节点进的晚,出的就早。if(node.right!=null){st.push(node.right);}//然后才是到左节点,晚点进就可以早点出。if(node.left!=null){st.push(node.left);}}return result;}
}
这是我第二写总结的流程:
1.初始化:
创建一个空的结果列表
创建一个辅助栈
将根节点压入栈中
2.主循环: 当栈不为空时,执行以下操作:
a. 处理当前节点:
从栈中弹出一个节点
将该节点的值添加到结果列表中
b. 压入子节点:
如果该节点有右子节点,将右子节点压入栈中
如果该节点有左子节点,将左子节点压入栈中
返回结果列表
这种方法的关键点在于:
根节点最先被处理,这符合前序遍历的"根-左-右"顺序。
右子节点先于左子节点入栈,这确保了左子节点会先于右子节点被处理。
这种非递归方法的优点是:
避免了递归调用的开销
对于深度很大的树,可以防止栈溢出
实现简单,易于理解
与中序遍历的非递归方法相比,前序遍历的非递归实现更为直观,因为它可以直接按照遍历顺序处理节点,而不需要像中序遍历那样先到达最左节点。
145.二叉树的后序遍历
递归写法
class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();dfs(root,result);return result;}public void dfs(TreeNode root,List<Integer> result){if(root==null){return;}dfs(root.left,result);dfs(root.right,result);result.add(root.val);}
}
非递归写法:
这个解法是一个技巧解。
由于前序遍历是根左右,而后续遍历是左右根。所以如果调整一下前序遍历的顺序,先加左节点,再加右节点,那么得到的结果就是按根右左规则得到的。所以此时做翻转,那么得到的结果就是按左右根得到的结果。与后序遍历的结果不谋而合。
所以解法就是线序遍历调整左右入栈方式,然后再对最终结果做翻转。
class Solution {public List<Integer> postorderTraversal(TreeNode root) {Deque<TreeNode> st = new ArrayDeque<>();List<Integer> result = new ArrayList<>();if(root==null){return result;}st.push(root);while(!st.isEmpty()){TreeNode node = st.pop();result.add(node.val);if(node.left!=null){st.push(node.left);}if(node.right!=null){st.push(node.right);}}Collections.reverse(result);return result;}
}
94.二叉树的中序遍历
递归写法
class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();dfs(root,result);return result;}public void dfs(TreeNode root,List<Integer> result){if(root==null){return;}dfs(root.left,result);result.add(root.val);dfs(root.right,result);}
}
非递归写法:
看这个图,然后结合图片,记下这个做法:
1.初始化:
创建一个空的结果列表和一个空的栈
将当前节点设置为根节点
2.主循环: 当当前节点不为空或栈不为空时,执行以下操作:
a. 左子树遍历:
如果当前节点不为空
将当前节点压入栈
移动到左子节点
b. 节点处理:
如果当前节点为空(即已经到达最左端)
从栈中弹出一个节点
将该节点的值添加到结果列表中
将当前节点移动到右子节点
3.返回结果列表
这种方法模拟了递归的过程:
首先尽可能深入地遍历左子树
然后处理节点本身
最后遍历右子树
使用栈来保存已经遍历过的父节点,以便在处理完左子树后能够回溯。
还是按代码思维走一遍,又和自己想的还是有一点区别。
class Solution {public List<Integer> inorderTraversal(TreeNode root) {//结果集List<Integer> result = new ArrayList<>();//特判if(root==null){return result;}//辅助栈Deque<TreeNode> st = new ArrayDeque<>();//用一个遍历指针指向rootTreeNode cur = root;//这里就是进递归处理的逻辑,循环条件决定了能不能递归处理下去。//cur!=null表明这个元素不空,可以进栈,!st.isEmpty(),是用来回溯的,表明栈中还有走过的元素需要进行处理。所以栈中走过的元素没处理完也要继续处理。while(cur!=null || !st.isEmpty()){//根据中序,左根右的走法,需要一路向最左下走。走的过程就一直入栈,保存之前的状态。如果cur==null,说明走到最左下的节点的左分支上了,也就是null。if(cur!=null){st.push(cur);cur = cur.left;}else{//不能继续往左走了才处理这里,这里就是开始回溯,回溯一下回到最左下的节点,此节点并不是null。那就把这个元素出栈,把这个元素的val加入结果集。由于每个元素都要左根右,这里处理了根节点,那还要往右节点走。下一波显然cur还是null,那么此时就会弹出沿着路线返回的根节点,往后都是这样。注意是依靠弹出的节点进行转移,因为栈里面的节点才是记录先前的状态,别自己瞎写一个。cur = st.pop();result.add(cur.val);cur = cur.right;}}//当st里面为空的时候,就是所有节点都处理完的时候。return result;}
}
102.二叉树的层序遍历
用队列。
看一个图就懂了。
队列先进先出,符合一层一层遍历的逻辑。
下面的代码就是二叉树层序遍历的模板题,会这个模板,之后遇到只要是层序遍历的题,随便杀。
总的来说,这个解法看完,里面的len的处理我是当时没想到的。
class Solution {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();checkFun(root,result);return result;}public void checkFun(TreeNode node,List<List<Integer>> result){//特判if(node==null){return;}//辅助队列Deque<TreeNode> que = new ArrayDeque<>();//根节点先入队que.offerLast(node);//队列不空就代表流程还没有结束while(!que.isEmpty()){//记录一层元素的结果集List<Integer> itemList = new ArrayList<Integer>();//在一开始先记录长度,该长度即队列目前的长度,就是该层元素的个数。//记录len就是为了做一个界限,即处理完这一层元素后,就要收集一次结果集。int len = que.size();//这个循环做依次将该层元素出队,并扩展其左右节点加入队列当中。while(len>0){//先出队TreeNode tmpNode = que.pollFirst();//加入结果集itemList.add(tmpNode.val);//扩展左右节点,加入队列中。if(tmpNode.left!=null){que.offerLast(tmpNode.left);}if(tmpNode.right!=null){que.offerLast(tmpNode.right);}//做完之后该层元素数量要-1len--;}//处理完一层后记录一次结果。result.add(itemList);}}
}
107.二叉树的层序遍历Ⅱ
在上题的基础上将结果集翻转就结束了。
class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {List<List<Integer>> result = new ArrayList<>();checkFun(root,result);Collections.reverse(result);return result;}public void checkFun(TreeNode node,List<List<Integer>> result){if(node==null){return;}Deque<TreeNode> que = new ArrayDeque<>();que.offerLast(node);while(!que.isEmpty()){List<Integer> itemList = new ArrayList<Integer>();int len = que.size();while(len>0){TreeNode tmpNode = que.pollFirst();itemList.add(tmpNode.val);if(tmpNode.left!=null){que.offerLast(tmpNode.left);}if(tmpNode.right!=null){que.offerLast(tmpNode.right);}len--;}result.add(itemList);}}
}
相关文章:
java算法day11
二叉树的递归遍历二叉树的非递归遍历写法层序遍历 递归怎么写? 按照三要素可以保证写出正确的递归算法: 1.确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且…...
linux下安装cutecom串口助手;centos安装cutecom串口助手;rpm安装包安装cutecom串口助手
在支持apt-get的系统下安装 在终端命令行中输入: sudo apt-get install cutecom 安装好后输入 sudo cutecom 就可以了 关于如何使用,可以看这个https://www.cnblogs.com/xingboy/p/14388610.html 如果你的电脑不支持apt-get。 那我们就通过安装包…...
2024年信息系统项目管理师2批次上午客观题参考答案及解析(1)
1、关于收集需求管理过程及相关技术的描述,正确的是() A.需求跟踪矩阵是把产品需求从其来源链接到能满足需求的可交付成果的一种表格 B.原型法是一种结构化的头脑风暴形式,通过投票排列最有用的创意 C&am…...
Xinstall揭秘:APP推广数据背后的真相,让你的营销更精准!
在这个移动互联网时代,APP如同雨后春笋般涌现,但如何在这片红海中脱颖而出,成为每一个开发者与运营者面临的共同难题。其中,APP推广统计作为衡量营销效果、优化推广策略的关键环节,更是不可忽视的一环。今天࿰…...
科研绘图系列:R语言小提琴图(Violin Plot)
介绍 小提琴图(Violin Plot)是一种结合了箱线图和密度图的图表,它能够展示数据的分布密度和分布形状。以下是对小提琴图的详细解释: 小提琴图能表达: 数据分布:小提琴图通过在箱线图的两侧绘制曲线来展示数据的分布密度,曲线的宽度表示数据点的密度。集中趋势:箱线图部…...
【Vite】修改构建后的 index.html 文件名
在 Vite 项目中,默认构建 index.html 。但有时候我们需要修改 index.html 为其他文件名,比如 index-{时间戳}.html 。 我们可以这样配置 vite.config.js: import { defineConfig } from vite; import type { PluginOption } from vite;// 自…...
解决IDEA每次新建项目都需要重新配置maven的问题
每次打开IDEA都要重新配置maven,这是因为在DEA中分为项目设置和全局设置,这个时候我们就需要去到全局中设置maven了。我用的是IntelliJ IDEA 2023.3.4 (Ultimate Edition),以此为例。 第一步:打开一个空的IDEA,选择左…...
论文学习_Getafix: learning to fix bugs automatically
1. 引言 研究背景:现代生产代码库极其复杂并且不断更新。静态分析器可以帮助开发人员发现代码中的潜在问题(在本文的其余部分中称为错误),这对于在这些大型代码库中保持高代码质量是必要的。虽然通过静态分析尽早发现错误是有帮助的,但修复这些错误的问题在实践中仍然主要…...
Xilinx FPGA:vivado关于真双端口的串口传输数据的实验
一、实验内容 用一个真双端RAM,端口A和端口B同时向RAM里写入数据0-99,A端口读出单数并存入单端口RAM1中,B端口读出双数并存入但端口RAM2中,当检测到按键1到来时将RAM1中的单数读出显示到PC端,当检测到按键2到来时&…...
RedisTemplate 中序列化方式辨析
在Spring Data Redis中,RedisTemplate 是操作Redis的核心类,它提供了丰富的API来与Redis进行交互。由于Redis是一个键值存储系统,它存储的是字节序列,因此在使用RedisTemplate时,需要指定键(Key)…...
数据结构与算法基础篇--二分查找
必要前提:有序数组 算法简述:通过不断取中间值和目标target值进行比较(中间值:mid (left right) / 2) 如果目标值等于中间位置的值,则找到目标,返回中间位置如果目标值小于中间位置的值&…...
python xlsx 导出表格超链接
该Python脚本用于从Excel文件中的第一列提取所有超链接并保存到一个文本文件中。首先,脚本导入必要的库并定义输入和输出文件的路径。然后,它确保输出文件的目录存在。接着,脚本加载Excel文件并选择活动工作表。通过遍历第一列的所有单元格&a…...
Data Guard高级玩法:failover备库后,通过闪回恢复DG备库
作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等) 公众号:老苏畅谈运维 欢迎关注本人公众号,更多精彩与您分享…...
【Unity2D 2022:NPC】制作任务系统
一、接受任务 1. 编辑NPC对话脚本: (1)创建静态布尔变量用来判断ruby是否接受到任务 public class NPCDialog : MonoBehaviour {// 创建全局变量用来判断ruby是否接到任务public static bool receiveTask false; } (2ÿ…...
【C++深度学习】多态(概念虚函数抽象类)
✨ 疏影横斜水清浅,暗香浮动月黄昏 🌏 📃个人主页:island1314 🔥个人专栏:C学习 🚀 欢迎关注:👍点赞 &…...
Ubuntu 安装CGAL
一、什么是CGAL CGAL(Computational Geometry Algorithms Library)是一个广泛使用的开源库,主要用于计算几何算法的实现。该库提供了一系列高效、可靠和易于使用的几何算法和数据结构,适用于各种应用领域。以下是 CGAL 的主要功能…...
RK3568平台开发系列讲解(网络篇)netfilter框架
🚀返回专栏总目录 文章目录 一、Netfilter 介绍二、netfilter 简单案例三、防火墙功能一、Netfilter 介绍 Linux内核自2.4版本开始引入了Netfilter框架,这是一项重要的网络功能增强。Netfilter框架由Linux内核防火墙和网络维护者 Rusty Russell 所提出和实现。这个作者还基于…...
检测音视频文件的声压
FFmpeg使用 ebur128 滤镜检测声压,EBU R128 是欧洲广播联盟(European Broadcasting Union,简称 EBU)推荐的音频响度测量和归一化标准。 ffmpeg -i input_video.mp4 -filter_complex ebur128peaktrue -f null --f null -ÿ…...
计算机网络-HTTP常见面试题
目录 1. HTTP是什么?2. HTTP常见的状态码?3. HTTP 常见的字段有哪些?4. GET和POST有什么区别:5. GET 和POST方法都是安全和幂等的吗?6. HTTP缓存技术7. HTTP/1.1相比HTTP/1.0提高了什么性能?8. HTTP/2做了什…...
LNMP搭建Discuz和Wordpress
1、LNMP L:linux操作系统 N:nginx展示前端页面web服务 M:mysql数据库,保存用户和密码,以及论坛相关的内容 P:php动态请求转发的中间件 数据库的作用: 登录时验证用户名和密码 创建用户和密码 发布和…...
java中的构造器
Java 中的构造器(也称为构造方法)是一种特殊的方法,用于初始化对象的状态。在创建 Java 类的实例时,构造器会被自动调用。 构造器的定义: 构造器的名称必须与类名完全相同。构造器没有返回值类型,甚至不包括…...
机器学习筑基篇,Ubuntu 24.04 快速安装 PyCharm IDE 工具,无需激活!
[ 知识是人生的灯塔,只有不断学习,才能照亮前行的道路 ] Ubuntu 24.04 快速安装 PyCharm IDE 工具 描述:虽然在之前我们安装了VScode,但是其对于使用Python来写大型项目以及各类配置还是比较复杂的,所以这里我们还是推…...
从0开始基于transformer进行股价预测(pytorch版本)
目录 数据阶段两个问题开始利用我们的代码进行切分 backbone网络训练效果 感觉还行,没有调参数。源码比较长,如果需要我后续会发(因为太长了!!) 数据阶段 !!!注意&#…...
【多GPU训练方法】
一、数据并行 这是最常用的方法。整个模型复制到每个GPU上。训练数据被均匀分割,每个GPU处理一部分数据。所有GPU上的梯度被收集并求平均。通常使用NCCL(NVIDIA Collective Communications Library)等通信库实现。参数更新 使用同步后的梯度…...
2024年PMP考试备考经验分享
PMP是项目管理领域最重要的认证之一,本身是IT行业比较流行的证书,近几年在临床试验领域也渐渐流行起来,是我周围临床项PM几乎人手一个的证书。 考试时间:PMP认证考试形式为180道选择题,考试时间为3小时50分。 考试计划ÿ…...
MT3046 愤怒的象棚
思路: a[]存愤怒值;b[i]存以i结尾的,窗口里的最大值;c[i]存以i结尾的,窗口里面包含✳的最大值。 (✳为新大象的位置) 例:1 2 3 4 ✳ 5 6 7 8 9 则ans的计算公式b3b4c4c5c6b7b8b9…...
深入了解代理IP常见协议:区别与选择
代理服务器在网络使用中扮演着重要的角色,是您设备和互联网之间的中间层。它不仅可以增强网络访问的安全性和隐私保护,还可以提供许多灵活的应用。使用代理时,不同的协议类型对数据交换具有不同的规则和特征。常见的代理协议包括HTTP代理、HT…...
【Linux 线程】线程的基本概念、LWP的理解
文章目录 一、ps -L 指令🍎二、线程控制 一、ps -L 指令🍎 🐧 使用 ps -L 命令查看轻量级进程信息;🐧 pthread_self() 用于获取用户态线程的 tid,而并非轻量级进程ID;🐧 getpid() 用…...
Dify中的工具
Dify中的工具分为内置工具(硬编码)和第三方工具(OpenAPI Swagger/ChatGPT Plugin)。工具可被Workflow(工作流)和Agent使用,当然Workflow也可被发布为工具,这样Workflow(工…...
在Visutal Studio 2022中完成D3D12初始化
在Visutal Studio 2022中完成DirectX设备初始化 1 DirectX121.1 DirectX 简介1.2 DirectX SDK安装2 D3D12初始化2.1 创建Windwos桌面项目2.2 修改符合模式2.3 下载d3dx12.h文件2.4 创建一个异常类D3DException,定义抛出异常实例的宏ThrowIfFailed3 D3D12的初始化步骤3.1 初始化…...
做物流的网站都有什么/百度快速收录入口
KNN算法是一种数据分类算法,以距离样本k个最邻近数据的类别代表样本的类别,因此也叫作k-近邻算法。KNN算法是数据挖掘中最简单的方法之一,大致可分为以下几个步骤: 训练数据:原数据集中所有数据类别的数据。 测试数据&…...
怎么做建设网站首页/html家乡网站设计
征途手机版主推国战系统,其中国家刺探是什么呢?国战相关的问题有哪些呢?今天当乐网小编给大家带来相关内容的解答:Q:《征途》共有几个国家?A:10个国家,分别是吴、赵、越、楚、燕、唐…...
wordpress免费商城主题/潍坊自动seo
ASP.NET 支持两组性能计数器:系统和应用程序。前者在 ASP.NET 性能计数器对象中的 PerfMon 中公开;后者在 ASP.NET Applications 性能对象中公开。ASP.NET 性能对象中的 State Server Sessions 计数器(仅适用于在其中运行状态服务器的服务器计…...
大鹏网站建设公司/网页制作平台有哪些
1). 在面向对象的方法中,一个对象请求另一个对象为其服务的方式是通过发送A.调用语句B.命令C.口令D.消息正确答案:D2). 下列的( )原始类型在使用流时可以互换。A.byte和booleanB.char和intC.byte和charD.String和char正确答案:B答案解析&…...
用php做网站需要什么软件/google手机官网
系统管理员一致认为:部署和管理大型分布式系统非常复杂。如果您有数百个应用程序,则很难手动执行所有操作。为了克服这个问题,容器技术已被广泛应用于各种行业的大规模分布式系统中。容器是打包应用程序及其依存关系的软件部署单元。容器技术…...
28网站制作/推广策略都有哪些
需求:一开始返回顶部图标是隐藏的,当滚动到指定位置的时候,小图标就会显示出来,,点击图标,会缓动的返回顶部 技术点:window.scrollTo(x,y),浏览器显示区域跳转到指定的坐标 <!DOC…...