【算法训练营Day14】二叉树part4

文章目录

  • 找树左下角的值
  • 路径总和
  • 总结:递归函数的返回值
  • 路径总和 II
  • 总结:二叉树递归的思考
  • 从中序与后序遍历序列构造二叉树

找树左下角的值

题目链接:513. 找树左下角的值

解题逻辑:

使用层序遍历,将最后一层的第一个元素拿出来即可。

class Solution {public int findBottomLeftValue(TreeNode root) {Deque<List<Integer>> allItem = new LinkedList<>();Deque<TreeNode> que = new ArrayDeque<>();que.add(root);while(!que.isEmpty()) {List<Integer> row = new ArrayList<>();int count = que.size();while(count > 0) {TreeNode node = que.remove();count--;row.add(node.val);if(node.left != null) que.add(node.left);if(node.right != null) que.add(node.right);}allItem.add(row);}return allItem.removeLast().get(0);}
}

路径总和

题目链接:112. 路径总和

解题逻辑:

这个题可以当作257. 二叉树的所有路径这道题的延深,我们可以沿用此题的代码,最后遍历每条路径上的和是否有符合条件的即可。

class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {if(root == null) return false;Deque<Integer> path = new ArrayDeque<>();List<Integer> allPathsAdd = new ArrayList<>();getAllPath(root,path,allPathsAdd);for(Integer sum : allPathsAdd) if(targetSum == sum) return true;return false;}public void getAllPath(TreeNode node,Deque<Integer> path,List<Integer> allPathsAdd){path.add(node.val);if(node.left == null && node.right == null) {int add =  0;for(Integer num : path) add += num;allPathsAdd.add(add);}if(node.left != null) {getAllPath(node.left,path,allPathsAdd);path.removeLast();}if(node.right != null) {getAllPath(node.right,path,allPathsAdd);path.removeLast();}}
}

上面的代码是在257代码的基础上修改而来,这样其实效率并不是很高,因为我们相当于是把所有路径遍历了出来,然后再检验是否存在符合条件的路径,但其实我们在遍历的途中发现有一条路径已经符合条件了,那么就可以直接返回了,这样就大大提升了效率。

修改后的代码如下:

class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {if(root == null) return false;int count = 0;return getPathSum(root,count,targetSum);}public boolean getPathSum(TreeNode node,int count,int targetSum){count += node.val;if(node.left == null && node.right == null) {if(count == targetSum) return true;return false;}if(node.left != null) {boolean left = getPathSum(node.left,count,targetSum);if(left == true) return true;}if(node.right != null) {boolean right = getPathSum(node.right,count,targetSum);if(right == true) return true;}return false;}
}

总结:递归函数的返回值

递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

路径总和 II

题目链接:113. 路径总和 II

与上一题的区别在于,本题要寻找所有符合条件的路径,所以要遍历整棵树,并且我们对递归的返回值也不做处理,所以我们的递归方法可以不设置返回值。

代码如下:

class Solution {public List<List<Integer>> pathSum(TreeNode root, int targetSum) {if(root == null) return new ArrayList<List<Integer>>();List<Integer> path = new ArrayList<>();List<List<Integer>> result = new ArrayList<>();getPathSum(root,path,targetSum,result);return result;}public void getPathSum(TreeNode node,List<Integer> path,int targetSum,List<List<Integer>> result){path.add(node.val);if(node.left == null && node.right == null) {int count = 0;for(Integer num : path) count += num;if(count == targetSum) {List<Integer> deepCopy = new ArrayList<>();for (Integer obj : path) {deepCopy.add(obj); }result.add(deepCopy);   } return;}if(node.left != null) {getPathSum(node.left,path,targetSum,result);path.remove(path.size() - 1);}if(node.right != null) {getPathSum(node.right,path,targetSum,result);path.remove(path.size() - 1);}}
}

总结:二叉树递归的思考

在这里插入图片描述

遍历的选择:看中的逻辑中需不需要左右的参与

递归,是递和归的两个过程:

  • 参数是在递的过程中层层深入
  • 返回值是在归的过程中逐层向上返回
  • 而回溯算法的逻辑就在归的过程之后

从中序与后序遍历序列构造二叉树

题目链接:106. 从中序与后序遍历序列构造二叉树

解题逻辑:

首先要了解想要恢复一颗二叉树,那么一定需要两种遍历方法,其中中序遍历是一定需要的,而另一种遍历方式可以是前序、后序、层序遍历方式。

复原的原理如下图所示:

在这里插入图片描述

本题是考察通过中序和后序构造二叉树,其中后序遍历是用来确定根节点的,而中序是用来确定根节点的左右子树情况的。

本题选用后序遍历的递归方式,这样最后可以将左右子树的根节点拼接到二叉树的根节点左右。接下来从递归三部曲开始分析:

  • 递归的参数与返回值:返回值为TreeNode,而参数为前序列表与后序列表,接下来将会对他递归切割
  • 递归出口:当后序列表长度为0的时候,直接返回null。当后序列表的长度为1的时候,则直接根据这个值构建节点返回
  • 递归单层逻辑:
    • 取到后序列表的最后一个元素,作为当前递归根节点
    • 在中序列表中找到该元素
    • 根据该元素对中序列表、后序列表进行切割
    • 左递归获得左子节点
    • 右递归获得右子节点
    • 将左右子节点组装到根节点上
    • 返回根节点

代码如下:

class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {if(postorder.length == 0) return null;if(postorder.length == 1) return new TreeNode(postorder[0]);int devideNum = postorder[postorder.length - 1];TreeNode root = new TreeNode(devideNum);int[] inorderLeft = Arrays.copyOfRange(inorder, 0, findNum(inorder,devideNum));int[] postorderLeft = Arrays.copyOfRange(postorder, 0, inorderLeft.length);root.left = buildTree(inorderLeft,postorderLeft);int[] inorderRight;if(findNum(inorder,devideNum) == inorder.length - 1) {inorderRight = new int[0];}else {inorderRight = Arrays.copyOfRange(inorder, findNum(inorder,devideNum) + 1,inorder.length);}int[] postorderRight = Arrays.copyOfRange(postorder, postorderLeft.length, postorder.length - 1);root.right = buildTree(inorderRight,postorderRight);return root;}public int findNum(int[] nums,int target){for(int i = 0;i < nums.length;i++) {if(nums[i] == target) return i;}return -1;}
}

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

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

相关文章

工资系统如何计算工资

工资系统计算工资是一个集成数据收集、规则应用、自动核算和合规审核的自动化过程&#xff0c;以下是其核心原理和步骤&#xff0c;结合技术实现与法规要求进行说明&#xff1a;⚙️ 一、工资系统的基本框架与数据准备系统初始化与规则配置企业信息设置&#xff1a;录入公司名称…

车载通信架构 --- DoIP协议通信

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

基于Event Sourcing和CQRS的微服务架构设计与实战

基于Event Sourcing和CQRS的微服务架构设计与实战 业务场景描述 在电商系统中&#xff0c;订单的高并发写入与复杂的状态流转&#xff08;下单、支付、发货、退货等&#xff09;给传统的CRUD模型带来了挑战&#xff1a; 数据一致性难保证&#xff1a;跨服务事务处理复杂&#x…

初级安全课第二次作业

&#xff08;一&#xff09;xss-labs 1~8关 1、前期准备 &#xff08;1&#xff09;打开小皮面板&#xff0c;并启动Apache和MySQL&#xff08;2&#xff09;将 xss-labs放到 phpstudy_pro 的 WWW 目录下&#xff08;3&#xff09;访问连接&#xff1a;http://localhost/xss-la…

从零搭建智能搜索代理:LangGraph + 实时搜索 + PDF导出完整项目实战

传统的AI聊天系统往往局限于预训练数据的知识范围&#xff0c;无法获取实时信息。本文将详细阐述如何构建一个基于LangGraph的智能代理系统&#xff0c;该系统能够智能判断何时需要进行网络搜索、有效维护对话上下文&#xff0c;并具备将对话内容导出为PDF文档的功能。 本系统…

C语言分支和循环语句——猜数字游戏

分支语句的语法形式1. if(表达式)语句;2. if(表达式)语句1;else语句2;3. Switch(表达式){ case 1: break;case 2: break;case 3: break; default: break; }循环语句的语法形式1. while(表达式)语句 ;2. for&#xff08;表达…

Python设计模式深度解析:原型模式(Prototype Pattern)完全指南

Python设计模式深度解析&#xff1a;原型模式&#xff08;Prototype Pattern&#xff09;完全指南前言什么是原型模式&#xff1f;模式的核心组成实际案例&#xff1a;游泳比赛管理系统游泳者数据结构原型模式的实现深拷贝 vs 浅拷贝&#xff1a;核心概念解析浅拷贝&#xff08…

SAP-ABAP:SAP万能长度计算:DYNAMIC_OUTPUT_LENGTH 深度解析

&#x1f4cf; SAP ABAP 万能长度计算&#xff1a;DYNAMIC_OUTPUT_LENGTH 深度解析核心作用&#xff1a;智能计算数据对象在列表/ALV中的实际显示宽度 | 关键优势&#xff1a;多字节字符处理 | 格式感知 | 动态适配&#x1f50d; 一、核心功能与技术特性 &#x1f4ca; 数据类型…

20250720-2-Kubernetes 调度-资源限制对Pod调度的影响(1)_笔记

一、创建一个Pod的工作流程&#xfeff;1. k8s架构解析&#xfeff;组件交互模式: Kubernetes采用list-watch机制的控制器架构&#xff0c;实现组件间交互的解耦。各组件通过监控自己负责的资源&#xff0c;当资源发生变化时由kube-apiserver通知相关组件。类比说明: 类似小卖铺…

mobaxteam x11传输界面避坑

mobaxteam x11传输界面避坑 文章目录mobaxteam x11传输界面避坑1 windows系统必须下载xing2 配置1 windows系统必须下载xing 因为windows系统本身没有x服务。 2 配置 如图

flink sql如何对hive string类型的时间戳进行排序

在 Flink SQL 中对 Hive 表的 STRING 类型时间戳进行排序&#xff0c;需要先将字符串转换为时间类型&#xff0c;再基于时间类型排序。以下是具体方法和示例&#xff1a; 一、核心解决方案 1. 字符串转 TIMESTAMP 后排序 若 Hive 中的时间戳格式为 yyyy-MM-dd HH:mm:ss&#xf…

Linux:线程控制

线程概念线程&#xff08;Thread&#xff09;是进程&#xff08;Process&#xff09; 中的一个执行单元&#xff0c;是操作系统能够进行运算调度的最小单位。线程也被称为“轻量级进程”&#xff08;Lightweight Process, LWP&#xff09;。一个进程可以包含多个线程&#xff0…

React 学习(4)

核心API———createRoot、render方法1.createRoot 方法是创建react的根容器&#xff0c;就是react元素的插入位置&#xff0c;插入的dom会被转化成react元素&#xff0c;根容器内的内容都会被react管理&#xff0c;原有dom都会被删除。react17 根容器创建、渲染方式&#xff0…

ASP .NET Core 8集成Swagger全攻略

Swagger (现在称为 OpenAPI) 是一个用于描述 RESTful API 的规范&#xff0c;ASP.NET Core 内置支持通过 Swashbuckle 库生成 Swagger 文档。以下是在 ASP.NET Core 8 中实现 Swagger 的完整步骤。1、添加Swagger NuGet 包dotnet add package Swashbuckle.AspNetCore2、添加Swa…

【iOS】源码阅读(六)——方法交换

文章目录方法交换什么是Method-Swizzling方法交换核心API**1. 获取方法对象****2. 添加/替换方法实现****3. 交换方法实现****4. 获取方法信息****5. 修改方法实现****使用示例&#xff1a;完整的 Method-Swizzling 流程****注意事项**使用方法交换注意事项线程安全方法交换的影…

mysql运维问题解决:MySQL主从延迟(锁阻塞与读写分离)

小亦平台会持续给大家科普一些运维过程中常见的问题解决案例&#xff0c;运维朋友们可以在常见问题及解决方案专栏查看更多案例 问题概述 告警事件&#xff1a; 2023-07-28 03:31:39.571 首次触发主从延迟告警&#xff08;延迟1515秒&#xff09;2023-07-28 07:41:37 告警解除…

SSH 密钥

什么是 SSH 密钥 SSH 密钥就像是你电脑的“身份证”和“钥匙”&#xff0c; 用来安全登录另一台电脑&#xff08;服务器&#xff09;&#xff0c;而不需要每次输入密码。SSH 密钥是一种安全登录远程服务器的方式&#xff0c;由一对加密的“钥匙”组成&#xff1a;一个公钥 一个…

st-Gcn训练跳绳识别模型一:数据标注工具和标注流程

目录 工具展示和使用说明 工具标注后文件展示说明 json转换成单个npy文件 数据获取补充 工具展示和使用说明 文件名labelV.py集于PySide6实现&#xff1a; 通过选择视频来选择你要标注的视频&#xff0c;然后选择保存路径&#xff1a; 然后视频两个类别。当你看见视频中的人…

springboot跨域问题 和 401

springboot跨域问题 和 401 1.跨域import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotatio…

构建直播平台大体的流程

✅ 直播流程完整链路&#xff08;基于 SRS OBS 前后端&#xff09;&#x1f9cd;‍♂️ 用户操作流程&#xff1a;✅ 用户登录系统&#xff08;前端&#xff09;系统中校验用户身份&#xff08;JWT 等&#xff09;后端可能校验权限&#xff0c;比如“是否有开播资格”✅ 用户…