二叉树(4)------收尾

1)最大二叉树

654. 最大二叉树 - 力扣(LeetCode)

题目解析:

1)首先我们找到了整个数组中最大的元素作为我们的根节点,然后再从左区间中找到最大的元素作为当前根节点的左子树,然后再从右区间里面找到最大的元素作为根节点的右子树

2)本题中使用前序遍历的方式来构建一棵二叉树,像这种构建一颗二叉树的题目都是必须先进行遍历出根节点,然后再进行构建右树或者是左树

class Solution {public TreeNode createTree(int[] nums,int left,int right){if(left>right) return null;int maxIndex=left;int maxData=nums[left];for(int i=left+1;i<=right;i++){if(nums[i]>maxData){maxData=nums[i];maxIndex=i;}}TreeNode root=new TreeNode(maxData);root.left=createTree(nums,left,maxIndex-1);root.right=createTree(nums,maxIndex+1,right);return root;}public TreeNode constructMaximumBinaryTree(int[] nums) {return createTree(nums,0,nums.length-1);}
}

2)二叉树迭代器

​​​​ 173. 二叉搜索树迭代器 - 力扣(LeetCode)

思路1:我们可以将二叉搜索树做一次完全的中序遍历,获取中序遍历的结果并存放到数组中,随后我们可以利用数组本身来实现迭代器

class BSTIterator {private int index=-1;private List<Integer> result;public void dfs(TreeNode root){if(root==null) return;dfs(root.left);result.add(root.val);dfs(root.right);}public BSTIterator(TreeNode root) {result=new ArrayList<>();index=0;//记录当前遍历到哪一个位置dfs(root);}public int next() {return result.get(index++);}public boolean hasNext() {return index<result.size();}
}

思路2:除了递归的方法之外,我们还可以使用迭代的方式针对于整棵二叉树做中序遍历,但是我们无需对这棵二叉树做一个完整的中序遍历,只需要维护栈的情况即可

class BSTIterator {Stack<TreeNode> stack=new Stack<>();TreeNode current=null;public BSTIterator(TreeNode root) {this.current=root;}public int next() {while(current!=null){stack.push(current);current=current.left;}TreeNode node=stack.pop();current=node.right;return node.val;}public boolean hasNext() {return !stack.isEmpty()||current!=null;}
}

3)合并二叉树

解法1:深度优先遍历

同时遍历两颗二叉树的根节点左节点和右节点

class Solution {public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {if(root1==null) return root2;if(root2==null) return root1;TreeNode root=new TreeNode(root1.val+root2.val);root.left=mergeTrees(root1.left,root2.left);root.right=mergeTrees(root1.right,root2.right);return root;}
}

解法2:宽度优先遍历:

在这里面我们使用的是三个队列,第一个队列存放的是第一个二叉树的左右节点,第二个队列存放的是第二个二叉树的左右节点,第三个队列存放的是合并完之后的节点充当根节点;

class Solution {public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {if(root1==null) return root2;if(root2==null) return root1;Queue<TreeNode> queue1=new LinkedList<>();Queue<TreeNode> queue2=new LinkedList<>();Queue<TreeNode> queue=new LinkedList<>();queue1.add(root1);queue2.add(root2);TreeNode rootNode=new TreeNode(root1.val+root2.val);queue.add(rootNode);while(!queue1.isEmpty()&&!queue2.isEmpty()){TreeNode root=queue.poll();TreeNode node1=queue1.poll();TreeNode node2=queue2.poll();TreeNode left1=node1.left;TreeNode right1=node1.right;TreeNode left2=node2.left;TreeNode right2=node2.right;if(left1!=null||left2!=null){if(left1!=null&&left2!=null){TreeNode left=new TreeNode(left1.val+left2.val);root.left=left;queue.add(left);queue1.add(left1);queue2.add(left2);}else if(left1!=null){root.left=left1;}else if(left2!=null){root.left=left2;}}if(right1!=null||right2!=null){System.out.println(11);if(right1!=null&&right2!=null){TreeNode right=new TreeNode(right1.val+right2.val);root.right=right;queue.add(right);queue1.add(right1);queue2.add(right2);}else if(right1!=null){root.right=right1;}else if(right2!=null){root.right=right2;}}}return rootNode;}
}

4)二叉树的最大路径和

124. 二叉树中的最大路径和 - 力扣(LeetCode)

算法原理:本体还是使用后序遍历的方式来做的,因为进行计算二叉树的最大路径和,针对于每一个节点来说,都是采取这样的方式来进行计算的:

1)递推公式:当前节点的路径和=当前的结点的值+左节点向上最大路径+右节点向上路径和

2)而左右节点又是拥有着自己的路径和,而这些路径和又有可能是最大的路径和

3)节点向上最大路径:当前节点+Math.max(左子树的最大路径,右子树的最大路径)

在这里面dfs函数被赋予的任务就是得到一个根节点的向上返回的最大路径

4)相当于是说我们在求出从一个节点到叶子节点的最大路径和的过程中就更新了最终想要的结果

class Solution {//返回经过root的单边分支最大和,即Math.max(root, root+left, root+right)int max=Integer.MIN_VALUE;public int dfs(TreeNode root){if(root==null) return 0;//计算左边分支最大值,左边分支如果为负数还不如不选择int left=Math.max(dfs(root.left),0);
//计算右边分支最大值,右边分支如果为负数还不如不选择,left->root->right 作为路径与已经计算过历史最大值做比较int right=Math.max(dfs(root.right),0);//更新最终结果max=Math.max(left+root.val+right,max);//返回经过root的单边最大分支给当前root的父节点计算使用return root.val+Math.max(left,right);}public int maxPathSum(TreeNode root) {dfs(root);return max;}
}

5)验证二叉树的前序序列化

331. 验证二叉树的前序序列化 - 力扣(LeetCode)

解法1:将所有的#当作是一个叶子节点,所有的非#字符当成一个非叶子节点,那么最终要满足的条件就是度是0的叶子节点=度是2的节点+1

在没有针对于整个二叉树做先序遍历之前,叶子结点的数量一定是小于等于非叶子节点的数量的

class Solution {public boolean isValidSerialization(String str) {int leafCount=0;int nodeCount=0;String[] string=str.split(",");for(String s:string){if(leafCount>nodeCount) return false;if(s.equals(",")) continue;else if(s.equals("#")) leafCount++;else nodeCount++;}return nodeCount+1==leafCount;}
}
class Solution {public boolean isValidSerialization(String str) {int leafCount=0;int nodeCount=0;String[] strings=str.split(",");for(int i=strings.length-1;i>=0;i--){if(strings[i].equals("#")) leafCount++;else{if(leafCount>=2) leafCount--;else return false;}}return leafCount==1;}
}

6)二叉搜索树中的众数:

采用左中右中序遍历的方式来解决这道问题

class Solution {List<Integer> list=new ArrayList<>();int prev=Integer.MIN_VALUE;int count=0;int maxCount=-1;public void dfs(TreeNode root){if(root==null) return;dfs(root.left);
//更新count值if(prev==Integer.MIN_VALUE){count=1;}else if(prev==root.val){count++;}else count=1;
//更新最终结果if(count==maxCount) list.add(root.val);else if(count>maxCount){list.clear();list.add(root.val);maxCount=count;  }
//修改指针指向prev=root.val;dfs(root.right);}public int[] findMode(TreeNode root) {dfs(root);int[] nums=new int[list.size()];System.out.println(list);int i=0;for(int num:list){nums[i]=num;i++;}return nums;}
}
class Solution {public int MaxCount=Integer.MIN_VALUE;public int prev=Integer.MAX_VALUE;HashMap<Integer,Integer> map=new HashMap<>();public int count=0;public void dfs(TreeNode root){if(root==null) return;dfs(root.left);if(root.val==prev){count++;}else{count=1;}if(count>=MaxCount){MaxCount=count;map.put(root.val,MaxCount);}prev=root.val;dfs(root.right);}public int[] findMode(TreeNode root) {if(root.left==null&&root.right==null) return new int[]{root.val};dfs(root);List<Integer> list=new ArrayList<>();for(Map.Entry<Integer,Integer> entry:map.entrySet()){if(entry.getValue()==MaxCount){list.add(entry.getKey());}  }int[] result=new int[list.size()];int index=0;for(int num:list){result[index]=num;index++;}return result;}
}
控制台

7)二叉搜索树的最近公共祖先:

1)如果是单纯的针对于二叉树来说,最近公共祖先就是我们在左子树中进行寻找有没有出现过p或者是q,然后如果左子树中有,那么就直接返回根节点,然后再从右子树中进行寻找p或者是q,如果右子树中也没有,那么直接返回null,有的话直接返回根节点,只要左子树或者是右子树出现了p或者是q就像向上返回,当然这也是我们的重复子问题;

2)针对于这个题来说,本质上还是使用后序遍历的的方式来进行处理,因为左右根,我们可以在根节点拿到左右子树的信息,从而进行整合,然后最后将根节点向上返回

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root==null) return null;else if(p.val<root.val&&q.val>root.val) return root;else if(p.val>root.val&&q.val<root.val) return root;else if(p==root) return p;else if(q==root) return q;else{TreeNode root1=lowestCommonAncestor(root.left,p,q);TreeNode root2=lowestCommonAncestor(root.right,p,q);if(root1==null&&root2==null){return null;}else if(root1!=null&&root2==null){return root1;}else if(root1!=null&&root2!=null){return root;}else{return root2;}}}
}
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root==null) return root;if(p.val==root.val||q.val==root.val) return root;if(p.val<root.val&&q.val<root.val){TreeNode left=lowestCommonAncestor(root.left,p,q);System.out.println(left.val);if(left!=null) return left;}else if(p.val>root.val&&q.val>root.val){TreeNode right=lowestCommonAncestor(root.right,p,q);if(right!=null) return right;}return root;}
}

非递归代码:利用二叉搜索树的特性

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if(root==null) return null;while(root!=null){if(root.val>p.val&&root.val>q.val){root=root.left;}else if(root.val<p.val&&root.val<q.val){root=root.right;}else{return root;}}return null;}
}

8)路经总和:

目标是遍历到叶子结点的时候进行收集结果

class Solution {List<Boolean> list=new ArrayList<>();int sum=0;int targetSum=0;List<Integer> path=new ArrayList<>();public void dfs(TreeNode root){if(root==null) return;if(root.left==null&&root.right==null){sum+=root.val;if(sum==targetSum){list.add(true);}else{list.add(false);}sum-=root.val;return;}if(root.left!=null){path.add(root.val);sum+=root.val;dfs(root.left);sum-=root.val;path.remove(path.size()-1);}if(root.right!=null){path.add(root.val);sum+=root.val;dfs(root.right);sum-=root.val;path.remove(path.size()-1);}}public boolean hasPathSum(TreeNode root, int targetSum) {this.targetSum=targetSum;dfs(root);System.out.println(list);for(boolean flag:list){if(flag==true) return true;}return false;}
}

解法2:还是回溯+递归:

1)目的是当我们进行深度优先遍历的时候,遇到一个结点的时候就让sum-root.val就做一次减法,如果遇到叶子节点,况且此时我们的sum值被减为0了,说明沿着路径的节点进行相加和等于目标值

2)递归的结束出口也是我们收集结果的的一个出口:

class Solution {public boolean dfs(TreeNode root,int targetSum){if(root==null) return false;if(root.left==null&&root.right==null){targetSum=targetSum-root.val;if(targetSum==0) return true;else return false;//说明这个路径不是我所想要的路径}boolean flag1=false,flag2=false;
//将左子树是否出现了等于目标和的路径返回给根节点
if(root.left!=null)  flag1=dfs(root.left,targetSum-root.val);//回溯的过程做隐藏了
//将右子树是否出现了等于目标和的路径返回给根节点,回溯的过程体现在递归函数的下面
if(root.right!=null)  flag2=dfs(root.right,targetSum-root.val);
//向上一层进行返回return flag1||flag2;}public boolean hasPathSum(TreeNode root, int targetSum) {return dfs(root,targetSum);}
}

9)二叉树的最大直径 

算法原理:

1)首先求出一个根节点的左子树的深度,在求出右子树的深度

2)此时以当前根节点为二叉树的直径就是左子树的深度+右子树的深度

3)相当于是说在求出二叉树的高度的时候就可以直接更新结果了

543. 二叉树的直径 - 力扣(LeetCode)

class Solution {int max=0;public int getHeight(TreeNode root){if(root==null) return 0;if(root.left==null&&root.right==null) return 1;int leftHeight=getHeight(root.left);int rightHeight=getHeight(root.right);
//更新结果max=Math.max(max,leftHeight+rightHeight);
//返回树的高度return Math.max(leftHeight,rightHeight)+1;}public int diameterOfBinaryTree(TreeNode root) {getHeight(root);return max;}
}

10)二叉树的坡度:

563. 二叉树的坡度 - 力扣(LeetCode)

算法原理:二叉树的坡度就是左子树的节点之和和右子树的节点之和的差的绝对值

这道算法题是在递归的过程中在不断的进行更新结果值,其实本质上dfs被赋予的任务就是计算出每一个节点的左右子树之和+当前根节点之和

lass Solution {int sum=0;public int dfs(TreeNode root){if(root==null) return 0;int left=dfs(root.left);int right=dfs(root.right);sum=sum+Math.abs(left-right);return left+right+root.val;}public int findTilt(TreeNode root) {dfs(root);return sum;}
}

11)在二叉树中增加一行

 623. 在二叉树中增加一行 - 力扣(LeetCode)

12)二叉树的锯齿形层序遍历:

 103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)

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

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

相关文章

ruby send call 的简单使用

refer: ruby on rails - What does .call do? - Stack Overflow Ruby使用call 可以调用方法或者proc m 12.method("") # > method gets the method defined in the Fixnum instance # m.class # > Methodm.call(3) #> 15 # 3 is passed inside the…

基于最新导则下生态环评报告编制技术暨报告篇、制图篇、指数篇、综合应用篇系统性实践技能提升

查看原文>>>基于最新导则下生态环评报告编制技术暨报告篇、制图篇、指数篇、综合应用篇系统性实践技能提升 目录 专题一、生态环评报告编制规范 专题二、土地利用图 专题三、植被类型及植被覆盖度图 专题四、物种适宜生境分布图 专题五、生物多样性测定 专题六…

网神 SecGate 3600 防火墙任意文件上传漏洞复现(HW0day)

0x01 产品简介 网神SecGate3600下一代极速防火墙&#xff08;NSG系列&#xff09;是基于完全自主研发、经受市场检验的成熟稳定网神第三代SecOS操作系统 并且在专业防火墙、VPN、IPS的多年产品经验积累基础上精心研发的高性能下一代防火墙 专门为运营商、政府、军队、教育、大型…

Jenkins自动化打包脚本

一、背景 jenkins可以设置定时任务打包&#xff0c;也已手动点按钮打包&#xff0c;还可以通过执行http请求打包&#xff0c;今天我们就通过shell脚本&#xff0c;通过curl命令进行jenkins打包。 二、步骤 2.1 在jenkins上构建项目 设置触发器 2.2 通过shell脚本触发远程构…

springboot整合JMH做优化实战

这段时间接手项目出现各种问题&#xff0c;令人不胜烦扰。吐槽下公司做项目完全靠人堆&#xff0c;大上快上风格注定留下一地鸡毛&#xff0c;修修补补不如想如何提升同事代码水准免得背锅。偶然看到关于JMH对于优化java代码的直观性&#xff0c;于是有了这篇文章&#xff0c;希…

【JavaScript】jquery的导入方式有两种:本地导入和线上导入

前言 jQuery是一个用来代替JavaScript来快捷书写前端脚本语言的库&#xff0c;jQuery可以大大的简化复杂的js代码&#xff0c;使开发人员专注于实现页面的效果。 导入方式有两种 jQuery的导入方式有两种&#xff0c;一种是本地导入&#xff0c;一种是利用超链接导入。 方法…

SpringBoot 整合MyBatis

整合MyBatis 官方文档&#xff1a;http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/ Maven仓库地址&#xff1a;https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter/2.1.3 整合测试 导入 MyBatis 所需要的…

Python数据分析案例03——天气K均值聚类分析

聚类常用的算法肯定是K均值聚类了&#xff0c;本次案例采用陕西的十个地区的天气数据&#xff0c;构建特征&#xff0c;进行聚类分析。 首先数据都装在‘天气数据’这个文件夹里面&#xff0c;如图&#xff1a; 打开其中一个excel&#xff0c;长这个样子 下面开始数据处理 数据…

Django实现音乐网站 ⑼

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是后台对专辑、首页轮播图原有功能的基础上进行部分功能实现和显示优化。 目录 专辑功能优化 新增编辑 专辑语种改为下拉选项 添加单曲优化显示 新增单曲多选 更新歌手专辑数、专辑单曲数 获取歌手专辑数 保…

07-2_Qt 5.9 C++开发指南_二进制文件读写(stm和dat格式)

文章目录 1. 实例功能概述2. Qt预定义编码文件的读写2.1 保存为stm文件2.2 stm文件格式2.3 读取stm文件 3. 标准编码文件的读写3.1 保存为dat文件3.2 dat文件格式3.3 读取dat文件 4. 框架及源码4.1 可视化UI设计4.2 mainwindow.cpp 1. 实例功能概述 除了文本文件之外&#xff…

MGRE综合

实验 一、实验思路 1.先按照上图配置IP地址及环回 2.写缺省使公网可通 3.让R1、R4、R5每台路由器均成为中心站点形成全连网状结构拓扑 4.让R1成为中心站点R2R3为分支站点 5.分区域宣告ospf之后更改ospf在虚拟接口Tunnel工作方式为broadcast及让R1 当选DR 二、上虚拟机操作…

数字万用表测量基础知识--DMM的显示位数

概览 DMM&#xff08;即数字万用表&#xff09;是一种电气测试和测量仪器&#xff0c;可测量直流和交流信号的电压、电流和电阻。本文介绍如何正确使用和理解数字万用表(DMM)。 DMM的显示位数 数字万用表(DMM)可用于进行各种测量。在选择DMM或理解所使用的DMM时&#xff0c;首…

改进的麻雀算法优化最大相关峭度解卷积(SCSSA-MCKD),实现早期微弱故障诊断,MATLAB代码实现

01 引言 由于一些设备的早期故障产生的冲击十分微弱&#xff0c;易被系统噪声干扰&#xff0c;如何有效地对设备的原始故障信号进行降噪并增强信号中微弱冲击成分&#xff0c;是进行该类部件早期故障诊断的关键。 最大相关峭度解卷积&#xff08;MCKD&#xff09;通过解卷积运算…

Kotlin读写分离CopyOnWriteArrayList

Kotlin读写分离CopyOnWriteArrayList 基于读写分离思想Copy-On-Write(COW)设计的线程安全ArrayList变体&#xff0c;读读共享、写写互斥、读写互斥、写读互斥。读时直接读&#xff0c;不用加锁同步&#xff0c;线程安全。写/删/修改数据时复制一个副本&#xff0c;在新的List副…

【AI理论学习】手把手推导扩散模型:Diffusion Models(DDPM)

手把手推导扩散模型&#xff1a;Diffusion Models&#xff08;DDPM&#xff09; DDPM理论回顾前置知识过程详解Forward ProcessReverse Process DDPM算法伪代码训练部分采样部分 总结一下 参考链接 在这篇博客文章中&#xff0c;我们将深入研究 去噪扩散概率模型(也称为 DDPM&…

Linux Linux系统文件类型与文件权限

一、文件类型 &#xff08;1&#xff09;在windows系统中文件类型以文件的后缀名来区分&#xff0c;在Linux系统中文件类型不以后缀名来区分。注意编写c代码时必须写后缀名.c&#xff0c;不然C编译器不会编译该文件。 &#xff08;2&#xff09;在Linux系统中以文件的标志来区…

如何用SOLIDWORKS Simulation 避免共振现象

零件都有它的固有振动频率&#xff0c;称之为共振频率。当零部件的固有频率和激励频率相近时&#xff0c;对零部件的破坏是非常严重的&#xff0c;这就是我们说的共振。频率分析是设计师日常工作常见的设计验证。 今天给大家分享的是Simulation的频率分析操作方法&#xff1a; …

Linux配置QT Creator环境:ubuntu中安装QT Creator环境

一、前景 目前市面上很多公司使用QT Creator进行界面开发&#xff0c;基本都会选择在Linux环境进行&#xff0c;优点不仅是市场所需&#xff0c;更是方便后期代码的移植&#xff0c;相较于Windows系统&#xff0c;Linux系统移植性非常好。故此篇文章&#xff0c;介绍如何在Linu…

【深度学习注意力机制系列】—— CBAM注意力机制(附pytorch实现)

CBAM&#xff08;Convolutional Block Attention Module&#xff09;是一种用于增强卷积神经网络&#xff08;CNN&#xff09;性能的注意力机制模块。它由Sanghyun Woo等人在2018年的论文[1807.06521] CBAM: Convolutional Block Attention Module (arxiv.org)中提出。CBAM的主…

在工作中使用ChatGPT需要担心泄密问题吗?

​OpenAI的ChatGPT可以通过自动简化繁琐的任务&#xff0c;针对挑战性问题的提供创造性的解决方案来提高员工的生产力。但随着这项技术被整合到人力资源平台和其他工作场所中&#xff0c;它给各个企业带来了巨大的挑战。苹果、Spotify、Verizon和三星等大公司已禁止或限制员工在…