【数据结构】二叉树总结篇
遍历
递归
递归三部曲:
1.参数和返回值
2.终止条件
3.单层逻辑(遍历顺序)
var preorderTraversal = function(root) {
// 第一种let res=[];const dfs=function(root){if(root===null)return ;//先序遍历所以从父节点开始res.push(root.val);//递归左子树dfs(root.left);//递归右子树dfs(root.right);}//只使用一个参数 使用闭包进行存储结果dfs(root);return res;
迭代
借助栈或队列
前序和后序

前序遍历:
// 入栈 右 -> 左
// 出栈 中 -> 左 -> 右
var preorderTraversal = function(root, res = []) {if(!root) return res;const stack = [root];let cur = null;while(stack.length) {cur = stack.pop();res.push(cur.val);cur.right && stack.push(cur.right);cur.left && stack.push(cur.left);}return res;
};// 入栈 左 -> 右
// 出栈 中 -> 右 -> 左 结果翻转var postorderTraversal = function(root, res = []) {if (!root) return res;const stack = [root];let cur = null;do {cur = stack.pop();res.push(cur.val);cur.left && stack.push(cur.left);cur.right && stack.push(cur.right);} while(stack.length);return res.reverse();
};
中序
中序遍历:// 入栈 左 -> 右
// 出栈 左 -> 中 -> 右var inorderTraversal = function(root, res = []) {const stack = [];let cur = root;while(stack.length || cur) {if(cur) {stack.push(cur);// 左cur = cur.left;} else {// --> 弹出 中cur = stack.pop();res.push(cur.val); // 右cur = cur.right;}};return res;
};
层序
队列 当前层元素个数
var levelOrder = function(root) {//二叉树的层序遍历let res = [], queue = [];queue.push(root);if(root === null) {return res;}while(queue.length !== 0) {// 记录当前层级节点数!!!let length = queue.length;//存放每一层的节点!!!let curLevel = [];for(let i = 0;i < length; i++) {let node = queue.shift();curLevel.push(node.val);// 存放当前层下一层的节点node.left && queue.push(node.left);node.right && queue.push(node.right);}//把每一层的结果放到结果数组res.push(curLevel);}return res;
};
应用
反转二叉树
前序,若中序注意调整
var invertTree = function(root) {//1.前序//递归if(root==null)return null;//中,交换左右节点swap(root)//左invertTree(root.left);//右invertTree(root.right);return root ;//中序遍历的话:左中右(右传的也是左指针,因为先翻完左树,再交换左右树,交换完的左数成右树了,所以还得传左!!!)//迭代法if(!root)return null;let stack=[root];while(stack.length>0){let cur=stack.pop();swap(cur)if(cur.left)stack.push(cur.left);if(cur.right)stack.push(cur.right);}return root;// //层次遍历(广度优先)->队列if(!root)return null;let queue=[root];while(queue.length>0){let levelSize=queue.length;for(let i=0;i<levelSize;i++){let cur=queue.shift();swap(cur);if(cur.left)queue.push(cur.left);if(cur.right)queue.push(cur.right)}}return root;};function swap(node){left=node.left;node.left=node.right;node.right=left;}
对称二叉树
比较逻辑,后序遍历
var isSymmetric = function(root) {//比较节点const compare=function(root1,root2){//终止条件!!!,默认遇到底就返回true,所以只考虑那些为false的条件if(!root1 && !root2)return true;else if(root1===null&&root2!==null||root2===null&&root1!==null)return false;else if(root1.val!==root2.val) return false//单层递归逻辑let outside=compare(root1.left,root2.right);let inside=compare(root1.right,root2.left);return outside&&inside;}if(root === null) {return true;}return compare(root.left,root.right)
};
最大深度
后序 +1细节
var maxDepth = function(root) {//递归方法if(root===null){return 0}else{let left=maxDepth(root.left);let right=maxDepth(root.right);return Math.max(left,right)+1;}
};
最小深度
考虑左侧或右侧为空的情况,最小深度不是1而是另外计算算法

var minDepth = function(root) {//递归//重点:递归终止条件if(root===null)return 0;//叶子节点// if(!root.left&&!root.right) return 1;if(root.left===null){return minDepth(root.right)+1;}if(root.right===null){return minDepth(root.left)+1;}let left=minDepth(root.left);let right=minDepth(root.right);let result=Math.min(left,right)+1; return result;
}
完全二叉树的节点个数
普通二叉树解决
var countNodes = function(root) {//递归方法const getNumbers=function(root){//终止条件if(!root)return 0;let left=getNumbers(root.left);let right=getNumbers(root.right);return left+right+1;}return getNumbers(root)
}
利用完全二叉树性质+递归方法
//**终止条件// if(!root)return 0;// //定义左右节点// let left=root.left;// let right=root.right;// let leftDepth=0,rightDepth=0;// while(left){// left=left.left;// leftDepth++;// }// while(right){// right=right.right;// rightDepth++;// }// if(leftDepth===rightDepth){// return Math.pow(2,leftDepth+1)-1;// }// return countNodes(root.left)+countNodes(root.right)+1;
平衡二叉树⭐
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1

-1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
var isBalanced = function(root) {// //还是用递归三部曲 + 后序遍历 左右中 // //!!!当前左子树右子树高度相差大于1就返回-1,标识相差大于1的!!!!const getDepth=function(node){if(!node)return 0;//不为-1的所有数,用于标识//确定单层遍历逻辑let leftDepth=getDepth(node.left);//左子树高度// 当判定左子树不为平衡二叉树时,即可直接返回-1if(leftDepth===-1)return -1;let rightDepth=getDepth(node.right);if(rightDepth===-1)return -1;//判断左右子树高差if(Math.abs(leftDepth-rightDepth>1)){return -1;}else{return 1 + Math.max(leftDepth,rightDepth);}}return !(getDepth(root)===-1) };
二叉树的所有路径
回溯+递归算法
Javascript回溯算法大全——组合、分割、子集、排列和棋盘问题

回溯算法,就是将问题其抽象一棵树,而本次二叉树所有路径本身就是一棵树
var binaryTreePaths = function(root) {let res=[];const backtracking=(root,value)=>{//到叶子节点就返回if(!root.left&&!root.right){value+=root.val;res.push(value);return;}//前序,简单的回溯value+=root.val+"->";root.left&&backtracking(root.left,value);root.right&&backtracking(root.right,value)}backtracking(root,'');return res;
};
左叶子之和⭐
判断当前节点是不是左叶子是无法判断的,
必须要通过节点的父节点来判断其左孩子是不是左叶子: if(node.left !== null && node.left.left === null && node.left.right === null)
平时我们解二叉树的题目时,已经习惯了通过节点的左右孩子判断本节点的属性,而本题我们要通过节点的父节点判断本节点的属性。
后序遍历
var sumOfLeftLeaves = function(root) {//迭代let sum=0;let stack=[root];if(!root)return 0;while(stack.length){let cur=stack.pop();if(cur.left&&!cur.left.left&&!cur.left.right){sum+=cur.left.val;}cur.left&&stack.push(cur.left);cur.right&&stack.push(cur.right);}return sum;
}var sumOfLeftLeaves = function(root) {//采用后序遍历 递归遍历// 1. 确定递归函数参数const nodesSum = function(node) {// 2. 确定终止条件if(!node) {return 0;}let leftValue = nodesSum(node.left);let rightValue = nodesSum(node.right);// 3. 单层递归逻辑let midValue = 0;if(node.left && !node.left.left && !node.left.right) {midValue = node.left.val;}let sum = midValue + leftValue + rightValue;return sum;}return nodesSum(root);
}
找树左下角的值
var findBottomLeftValue = function(root) {//Todo:最大深度,最左侧的值// 层次遍历let queue=[root];if(!root)return null;let res;while(queue.length){let length=queue.length;for(let i=0;i<length;i++){let curNode=queue.shift();if(i===0){res=curNode.val;}curNode.left&&queue.push(curNode.left);curNode.right&&queue.push(curNode.right);}}return res;
}
路径总和⭐⭐
回溯算法
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @param {number} targetSum* @return {boolean}*/
var hasPathSum = function(root, targetSum) {//targetSum依次往下减,直至减到0且找到叶子节点,就找到路径if(!root)return false;let backtracking=(root,targetSum)=>{//到根节点且刚好和为targetSumif(targetSum===0&&!root.left&&!root.right) return true;// 遇到叶子节点而没有找到合适的边(计数不为0),直接返回if (!root.left&&!root.right) return false;if(root.left){targetSum-=root.left.valif(backtracking(root.left,targetSum)) return true;targetSum+=root.left.val}if(root.right){targetSum-=root.right.valif(backtracking(root.right,targetSum)) return true;targetSum+=root.right.val}return false;}return backtracking(root,targetSum-root.val);
};
路径总和II⭐⭐
处理根节点逻辑
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @param {number} targetSum* @return {number[][]}*/
var pathSum = function(root, targetSum) {let res=[]if(!root)return res;let path=[root.val];let backtracking=(root,sum)=>{if(!root.left&&!root.right&&sum===targetSum){res.push(path.slice());return;}if(!root.left&&!root.right)return;//左if(root.left){path.push(root.left.val);sum+=root.left.val;backtracking(root.left,sum);sum-=root.left.val;path.pop();}//右if(root.right){path.push(root.right.val);sum+=root.right.val;backtracking(root.right,sum);sum-=root.right.val;path.pop();}return;}backtracking(root,root.val)return res;
}
从中序与后序遍历序列构造二叉树

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*/
/*** @param {number[]} inorder* @param {number[]} postorder* @return {TreeNode}*/
var buildTree = function(inorder, postorder) {//中序:左中右//后序:左右中//返回条件if(!postorder.length)return null;//1.从后序找到中间节点let midVal=postorder.pop();let root=new TreeNode(midVal);//左中序,右后序let index=inorder.indexOf(midVal);//找到中序的mid对应的索引root.left=buildTree(inorder.slice(0,index),postorder.slice(0,index));root.right=buildTree(inorder.slice(index+1),postorder.slice(index));return root;
};
从前序与中序遍历序列构造二叉树
/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*/
/*** @param {number[]} preorder* @param {number[]} inorder* @return {TreeNode}*/
var buildTree = function(preorder, inorder) {//前序:中左右//中序:左中右if(!preorder.length)return null;let midVal=preorder.shift();let index=inorder.indexOf(midVal);let root=new TreeNode(midVal);root.left=buildTree(preorder.slice(0,index),inorder.slice(0,index));root.right=buildTree(preorder.slice(index),inorder.slice(index+1));return root;
};
最大二叉树

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val = (val===undefined ? 0 : val)* this.left = (left===undefined ? null : left)* this.right = (right===undefined ? null : right)* }*/
/*** @param {number[]} nums* @return {TreeNode}*/
var constructMaximumBinaryTree = function(nums) {//构建二叉树类型题目——前序遍历if(!nums.length)return null;//1.找最大let max=-1,maxIndex=-1;for(let i=0;i<nums.length;i++){if(nums[i]>max){max=nums[i];maxIndex=i;}}//2.构建根节点let root =new TreeNode(max);//构建左边root.left=constructMaximumBinaryTree(nums.slice(0,maxIndex));//构建右边root.right=constructMaximumBinaryTree(nums.slice(maxIndex+1));return root;
};
相关文章:
【数据结构】二叉树总结篇
遍历 递归 递归三部曲: 1.参数和返回值 2.终止条件 3.单层逻辑(遍历顺序) var preorderTraversal function(root) { // 第一种let res[];const dfsfunction(root){if(rootnull)return ;//先序遍历所以从父节点开始res.push(root.val);//递归…...
软考-数据库开发工程师-3.1-数据结构-线性结构
第3章内容比较多,内容考试分数占比较大,6分左右 线性表 1、线性表的定义 一个线性表是n个元素的有限序列(n≥0),通常表示为(a1,a2, a3,…an). 2、线性表的顺序存储(顺序表) 是指用一组地址连续的存储单元依次存储线性表中的数据元…...
【五.LangChain技术与应用】【2.LangChain虚拟环境搭建(下):环境优化与调试】
一、Docker化部署:别让你的环境成为薛定谔的猫 经历过"在我机器上能跑"惨案的老铁都懂,传统虚拟环境就像个黑盒子。去年我帮客户部署LangChain应用,因为glibc版本差了0.1,整个服务直接崩成烟花。从那天起,我所有项目都强制上Docker! Dockerfile生存指南: #…...
deepseek+mermaid【自动生成流程图】
成果: 第一步打开deepseek官网(或百度版(更快一点)): 百度AI搜索 - 办公学习一站解决 第二步,生成对应的Mermaid流程图: 丢给deepseek代码,或题目要求 生成mermaid代码 第三步将代码复制到me…...
Java实现大数据量导出报表
一、实现方式 在Java中,导出数据到Excel有多种方式,每种方式都有其优缺点,适用于不同的场景。以下是常见的几种方式及其特点: 1.1 Apache POI Apache POI 是 Java 中最流行的库,支持读写 Excel 文件(包括…...
在 Element Plus 的 <el-select> 组件中,如果需要将 <el-option> 的默认值设置为 null。 用于枚举传值
文章目录 引言轻松实现 `<el-option>` 的默认值为 `null`I 实现方式监听清空事件 【推荐】使用 v-model 绑定 null添加一个值为 null 的选项处理 null 值的显示引言 背景:接口签名规则要求空串参与,空对象不参与签名计算 // 空字符串“” 参与签名组串,null不参与签…...
Spring Boot 接口 JSON 序列化优化:忽略 Null 值的九种解决方案详解
一、针对特定接口null的处理: 方法一:使用 JsonInclude 注解 1.1 类级别:在接口返回的 DTO 类或字段 上添加 JsonInclude 注解,强制忽略 null 值: 类级别:所有字段为 null 时不返回 JsonInclude(Js…...
解码未来!安徽艾德未来智能科技有限公司荣获“GAS消费电子科创奖-产品创新奖”!
在2025年“GAS消费电子科创奖”评选中,安徽艾德未来智能科技有限公司提交的“讯飞AI会议耳机iFLYBUDS Pro 2”,在技术创新性、设计创新性、工艺创新性、智能化创新性及原创性五大维度均获得评委的高度认可,荣获“产品创新奖”。 这一殊荣不仅…...
Velox 之 Expression
Round 函数 velox/functions/prestosql/Arithmetic.h template <typename T> struct RoundFunction {template <typename TInput>FOLLY_ALWAYS_INLINE voidcall(TInput& result, const TInput& a, const int32_t b = 0) {result = round(a, b);} };/// R…...
【零基础到精通Java合集】第二十四集:ZGC收集器详解
课程标题:ZGC收集器——突破停顿时间极限的下一代垃圾回收器(15分钟) 目标:掌握ZGC的核心技术原理、适用场景与调优策略,理解其如何实现亚毫秒级停顿 0-1分钟:课程引入与ZGC设计目标 以“高速公路无障碍通行”类比ZGC核心思想:通过染色指针与读屏障技术,实现垃圾回收…...
力扣hot100刷题——栈
文章目录 69.有效的括号题目描述思路:栈code 70.最小栈题目描述思路:双栈法code优化:单栈法code 71.字符串解码题目描述思路:栈code 73.每日温度题目描述思路:单调栈code 74.柱状图中最大的矩形题目描述思路࿱…...
TMS320F28P550SJ9学习笔记2:Sysconfig 配置与点亮LED
今日学习使用Sysconfig 对引脚进行配置,并点亮开发板上的LED4 与LED5 我的单片机开发板平台是 LAUNCHXL_F28P55x 我是在上文描述的驱动库C2000ware官方例程example的工程基础之上进行添加功能的 该例程路径如下:D:\C2000Ware_5_04_00_00\driverlib\f28p…...
STM32MP1xx的启动流程
https://wiki.st.com/stm32mpu/wiki/Boot_chain_overview 根据提供的知识库内容,以下是STM32 MPU启动链的详细解析: 1. 通用启动流程 STM32 MPU启动分为多阶段,逐步初始化外设和内存,并建立信任链: 1.1 ROM代码&…...
开源之夏经验分享|Koupleless 社区黄兴抗:在开源中培养工程思维
开源之夏经验分享|Koupleless 社区黄兴抗:在开源中培养工程思维 文|黄兴抗 电子信息工程专业 Koupleless 社区贡献者 就读于南昌师范学院,电子信息工程专业的大三学生。 本文 2634 字,预计阅读 7 分钟 今天 SOFAStack 邀…...
健康养生:开启活力人生的钥匙
在快节奏的现代生活中,健康养生已成为我们追求美好生活的关键。它不仅关乎身体的强健,更与心灵的宁静息息相关。 合理饮食是健康养生的基石。多吃蔬菜、水果,它们富含维生素与矿物质,为身体提供充足养分。全谷物食品也是不错的选…...
HTTP 与 HTTPS 协议:从基础到安全强化
引言 互联网的消息是如何传递的? 是在路由器上不断进行跳转 IP的目的是在寻址 HTTP 协议:互联网的基石 定义 HTTP(英文:HyperText Transfer Protocol,缩写:HTTP),即超文本传输协…...
项目工坊|Python驱动淘宝信息爬虫
目录 前言 1 完整代码 2 代码解读 2.1 导入模块 2.2 定义 TaoBao 类 2.3 search_infor_price_from_web 方法 2.3.1 获取下载路径 2.3.2 设置浏览器选项 2.3.3 反爬虫处理 2.3.4 启动浏览器 2.3.5 修改浏览器属性 2.3.6 设置下载行为 2.3.7 打开淘宝登录页面 2.3.…...
SQLite Alter 命令详解
SQLite Alter 命令详解 SQLite 是一种轻量级的数据库,广泛用于各种嵌入式系统、移动应用和小型项目。SQLite 的ALTER TABLE命令用于修改已存在的表结构,包括添加、删除或修改列,以及重命名表等操作。本文将详细解析SQLite的ALTER TABLE命令&…...
【Linux】冯诺依曼体系结构-操作系统
一.冯诺依曼体系结构 我们所使用的计算机,如笔记本等都是按照冯诺依曼来设计的: 截止目前,我们所知道的计算机都是由一个一个的硬件组装起来的,这些硬件又由于功能的不同被分为了输入设备,输出设备,存储器…...
mapbox进阶,使用点类型geojson加载symbol符号图层,用于标注带图标的注记,且文字居中在图标内,图标大小自适应文字
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象…...
布隆过滤器(附带位图讲解)
提到位图,我们首先想到的应该是它的两面定义: 位图图像(bitmap),亦称为点阵图或栅格图像,是由称作像素(图片元素)的单个点组成的。位图是指内存中连续的二进制位,用于对…...
【芯片设计】AI偏车载芯片前端设计工程师面试记录·20250304
【芯片前端设计面试经验专栏介绍】 专栏聚焦数字芯片前端设计核心技术与面试方法论,涵盖架构设计、RTL开发、验证方法学、低功耗设计、时序收敛等高频考点,深入解析行业头部企业的面试真题与设计场景。内容包含但不限于: 知识点系统梳理 :从Verilog/SV语法陷阱、FSM设计模式…...
2024北京理工大学计算机复试上机真题
2024北京理工大学计算机复试上机真题 2024北京理工大学计算机考研复试上机真题 在线评测:https://app2098.acapp.acwing.com.cn/ 等腰梯形 题目描述 请输入高度h,输入一个高为h,上底边长为h的等腰梯形(例如h4,图形…...
CC++的内存管理
目录 1、C/C内存划分 C语言的动态内存管理 malloc calloc realloc free C的动态内存管理 new和delete operator new函数和operator delete函数 new和delete的原理 new T[N]原理 delete[]的原理 1、C/C内存划分 1、栈:存有非静态局部变量、函数参数、返回…...
Redis是什么?如何使用Redis进行缓存操作?
Redis(Remote Dictionary Server)是一款高性能的内存键值存储系统,广泛用于缓存、消息队列、会话存储和实时数据处理等场景。它基于内存存储,支持多种数据结构,如字符串、列表、集合、有序集合和哈希表等,具…...
【商城实战(2)】商城架构设计:从底层逻辑到技术实现
【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配…...
USB 模块 全面解析(一)
本文是我整理的一些 USB 的学习心得,希望能对大家有所帮助。 文章目录 前言🍒 USB 基本概述🍒 USB 结构框架🍉硬件框架🍉 软件框架 🍒 USB 电气信号🍉 USB 硬件线路🍉 信号电平&…...
xr-frame 3D Marker识别,扬州古牌坊 3D识别技术稳定调研
目录 识别物体规范 3D Marker 识别目标文件 map 生成 生成任务状态解析 服务耗时: 对传入的视频有如下要求: 对传入的视频建议: 识别物体规范 为提高Marker质量,保证算法识别效果,可参考Marker规范文档 Marker规…...
拆一拆吉利普及高阶智驾的盲盒
吉利银河后续所有的全新和改款车型都会搭载千里浩瀚不同级别的智驾系统; 既然银河都标配了,定位更高的领克大概率也会全系标配; 加上极氪从去年下半年就是全系标配。 这样一来,就是吉利版的「全民智驾」。 一、 「千里浩瀚」&a…...
2024四川大学计算机考研复试上机真题
2024四川大学计算机考研复试上机真题 2024四川大学计算机考研复试机试真题 历年四川大学计算机考研复试机试真题 在线评测:https://app2098.acapp.acwing.com.cn/ 分数求和 题目描述 有一分数序列: 2/1 3/2 5/3 8/5 13/8 21/13… 求出这个数列的前 …...
