二叉树(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)

解法1:深度优先遍历:直接从根节点向下进行深度优先遍历,深度++,当遍历到对应的深度的时候直接向下添加节点即可,但是下面这种写法有问题

 

class Solution {public int insertDepth;public TreeNode addOneRow(TreeNode root, int val, int depth) {this.insertDepth=depth;//特殊处理要插入的位置是第一层if(depth==1){TreeNode node=new TreeNode(val);node.left=root;return node;}dfs(root,val,1);return root;}public void dfs(TreeNode root,int val,int depth){if(root==null) return;if(depth==insertDepth-1){TreeNode left=root.left;TreeNode right=root.right;root.left=new TreeNode(val);root.right=new TreeNode(val);root.left.left=left;root.right.right=right;return;}dfs(root.left,val,depth+1);dfs(root.right,val,depth+1);}
}

解法2:宽度优先遍历:

class Solution {public TreeNode addOneRow(TreeNode root, int val, int depth) {Queue<TreeNode> queue=new LinkedList<>();int insertDepth=1;queue.add(root);List<TreeNode> list=new ArrayList<>();list.add(root);
//特殊处理要插入的位置是第一层if(depth==1){TreeNode node=new TreeNode(val);node.left=root;return node;}
//这个for循环的目的是将depth-1层的节点全部添加到list中for(int i=1;i<depth-1;i++){List<TreeNode> temp=new ArrayList<>();for(TreeNode node:list){if(node.left!=null) temp.add(node.left);if(node.right!=null) temp.add(node.right);}list=temp;}for(TreeNode node:list){TreeNode left=node.left;TreeNode right=node.right;node.left=new TreeNode(val);node.right=new TreeNode(val);node.left.left=left;node.right.right=right;}return root;}
}

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

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

层序遍历+双端队列+双向链表(可以进行头插,也可以进行尾插)

class Solution {public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> ret=new ArrayList<>();Queue<TreeNode> queue=new LinkedList<>();queue.add(root);if(root==null) return ret;while(!queue.isEmpty()){LinkedList<Integer> temp=new LinkedList<>();int size=queue.size();for(int i=0;i<size;i++){TreeNode node=queue.poll();if(ret.size()%2==0){temp.addLast(node.val);}else{temp.addFirst(node.val);}if (node.left!= null) queue.add(node.left);if (node.right!= null) queue.add(node.right);}ret.add(temp);}return ret;}
}

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

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

相关文章

直接在html中引入Vue.js的cdn来实现一个简单的博客

摘要 其实建立一个博客系统是非常简单的&#xff0c;有很多开源的程序&#xff0c;如果你不喜欢博客系统&#xff0c;也可以自己开发&#xff0c;也可以自己简单做一个。我这次就是用Vue.js和php做后端服务实现一个简单的博客。 界面 代码结构 代码 index.html <!DOCTYP…

maven的入门使用

maven的入门使用 1.Maven&#xff08;Maven Apache&#xff09;是一个流行的项目构建和管理工具&#xff0c;2.项目结构和POM文件&#xff1a;3.POM文件&#xff08;Project Object Model&#xff09;4.依赖管理&#xff1a; 在POM文件中5.生命周期和构建过程1.前言2.插件系统3…

uni-app使用vue语法进行开发注意事项

目录 uni-app 项目目录结构 生命周期 路由 路由跳转 页面栈 条件编译 文本渲染 样式渲染 条件渲染 遍历渲染 事件处理 事件修饰符 uni-app 项目目录结构 组件/标签 使用&#xff08;类似&#xff09;小程序 语法/结构 使用vue 具体项目目录如下&#xff1a; 生命…

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

深度学习中的注意力机制&#xff08;Attention Mechanism&#xff09;是一种模仿人类视觉和认知系统的方法&#xff0c;它允许神经网络在处理输入数据时集中注意力于相关的部分。通过引入注意力机制&#xff0c;神经网络能够自动地学习并选择性地关注输入中的重要信息&#xff…

Scikit-learn聚类方法代码批注及相关练习

一、代码批注 代码来自&#xff1a;https://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html#sphx-glr-auto-examples-cluster-plot-dbscan-py import numpy as np from sklearn.cluster import DBSCAN from sklearn import metrics from sklearn.datasets …

DNS部署与安全详解(下)

文章目录 前言一、指定区域解析配置二、DNS服务器对外名称显示配置三、转发器使用配置四、配置辅助&#xff08;备份&#xff09;服务器五、如何让虚拟机可以真实上网六、为DNS服务器配置别名 前言 上一篇博客我们已经在Windows server2003的虚拟机上下载了DNS软件&#xff0c;…

SQL-每日一题【1251. 平均售价】

题目 Table: Prices Table: UnitsSold 编写SQL查询以查找每种产品的平均售价。average_price 应该四舍五入到小数点后两位。 查询结果格式如下例所示&#xff1a; 解题思路 1.题目要求查询每种产品的平均售价。给出了两个表&#xff0c;我们用聚合查询来解决此问题。 2.首先我…

Samba(二)

问题 Rocky Linux使用smbclient访问win11的共享文件时提示 Error NT_STATUS_IO_TIMEOUT 分析 通过测试&#xff0c;发现关闭windows公用网络防火墙时&#xff0c;可正常显示服务器端所分享出来的所有资源&#xff1b;进一步发现单独放行防火墙进站规则中的文件和打印机共享&a…

20、stm32使用FMC驱动SDRAM(IS42S32800G-6BLI)

本文将使用安富莱的STM32H743XIH板子驱动SDRAM 引脚连接情况 一、CubeMx配置工程 1、开启调试口 2、开启外部高速时钟 配置时钟树 3、开启串口1 4、配置MPU 按照安富莱的例程配置&#xff1a; /* ********************************************************************…

什么是POP3协议?

POP3&#xff08;Post Office Protocol Version 3&#xff09;是一个用于从电子邮件服务器获取邮件的应用层协议。以下是关于POP3的详细解释&#xff1a; 基本操作&#xff1a;使用POP3&#xff0c;电子邮件客户端可以从邮件服务器上下载电子邮件&#xff0c;并将其保存在本地。…

【JPCS出版】第五届能源、电力与电网国际学术会议(ICEPG 2023)

第五届能源、电力与电网国际学术会议&#xff08;ICEPG 2023&#xff09; 2023 5th International Conference on Energy, Power and Grid 最近几年&#xff0c;不少代表委员把目光投向能源电力领域&#xff0c;对促进新能源发电产业健康发展、电力绿色低碳发展&#xff0c;提…

cpu的架构

明天继续搞一下cache,还有后面的, 下面是cpu框架图 开始解释cpu 1.控制器 控制器又称为控制单元&#xff08;Control Unit&#xff0c;简称CU&#xff09;,下面是控制器的组成 1.指令寄存器IR:是用来存放当前正在执行的的一条指令。当一条指令需要被执行时&#xff0c;先按…

【C语言】指针的进阶2

指针进阶 函数指针数组指向函数指针数组的指针回调函数指针和数组经典题目的解析 函数指针数组 数组是一个存放相同类型数据的存储空间&#xff0c;那我们已经学习了指针数组&#xff0c; 比如&#xff1a; int* arr[10];//数组的每个元素是int*那要把函数的地址存到一个数组…

无涯教程-Perl - getpwnam函数

描述 此函数基于EXPR指定的用户名,从/etc/passwd文件提取的列表context中返回字段列表。通常这样使用- ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) getpwnam($user); 在标量context中,返回数字用户ID。如果尝试访问整个/etc/passwd文件,则应使用getpwent…

Lecoode有序数组的平方977

题目建议&#xff1a; 本题关键在于理解双指针思想 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 双指针法经典题目 | LeetCode&#xff1a;977.有序数组的平方_哔哩…

【Linux】内核宏定义解释postcore_initcall,arch_initcall,subsys_initcall

postcore_initcall postcore_initcall(pcibus_class_init) 是一个宏&#xff0c;用于在Linux内核初始化过程中注册一个后期初始化函数。 这个宏的含义如下&#xff1a; postcore_initcall 是一个宏定义&#xff0c;用于指定注册的函数在内核初始化的哪个阶段执行。 pcibus_cl…

Spring Gateway+Security+OAuth2+RBAC 实现SSO统一认证平台

背景&#xff1a;新项目准备用SSO来整合之前多个项目的登录和权限&#xff0c;同时引入网关来做后续的服务限流之类的操作&#xff0c;所以搭建了下面这个系统雏形。 关键词&#xff1a;Spring Gateway, Spring Security, JWT, OAuth2, Nacos, Redis, Danymic datasource, Jav…

nginx代理服务、网关配置

一、nginx安装在服务器&#xff0c;本机运行服务&#xff0c;如何使用远程nginx代理本机服务&#xff1f; 打开nginx配置文件&#xff0c;位置&#xff1a;/usr/local/nginx/conf/nginx.conf&#xff0c;在http模块中添加以下server代码段&#xff1a; http {server {listen …

Stable Diffusion - 人物坐姿 (Sitting) 的提示词组合 与 LoRA 和 Embeddings 配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132201960 拍摄人物坐姿时&#xff0c;需要注意&#xff1a; 选择一个舒适和自然的坐姿&#xff0c;符合个性和心情。可以坐在椅子、沙发、长凳、…

ubuntu安装docker-compose

1.官方安装链接 访问&#xff1a;https://docs.docker.com/compose/install/standalone/ 链接&#xff0c;可以看到如下页面&#xff0c;使用下面圈起来的命令即可 2.安装 使用该命令进行安装&#xff0c;很慢&#xff0c;一直卡着不动&#xff0c;原因是从github中下载&am…