经典算法题总结:二叉树篇

二叉树解题的思维模式分两类:

  1. 是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。
  2. 是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。

无论使用哪种思维模式,你都需要思考:如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。

二叉树数据结构定义:

public class TreeNode {int val;TreeNode left;TreeNode right;public TreeNode() {}public TreeNode(int val) {this.val = val;}public TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}

102. 二叉树的层序遍历(⭐️⭐️)

思路

代码

public class LevelOrder {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> res = new ArrayList<>();Queue<TreeNode> queue = new LinkedList<>();if (root != null) {queue.add(root);}while (!queue.isEmpty()) {int n = queue.size();List<Integer> level = new ArrayList<>();for (int i = 0; i < n; i++) {TreeNode node = queue.poll();level.add(node.val);if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}res.add(level);}return res;}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(N)

236. 二叉树的最近公共祖先(⭐️⭐️)

思路

代码

public class LowestCommonAncestor {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null || root == p || root == q) {return root;}TreeNode left = lowestCommonAncestor(root.left, p, q);TreeNode right = lowestCommonAncestor(root.right, p, q);if (left == null && right == null) {return null;} else if (left == null && right != null) {return right;} else if (left != null && right == null) {return left;} else {return root;}}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(log(N))

103. 二叉树的锯齿形层序遍历(⭐️⭐)

思路

代码

import java.util.LinkedList;
import java.util.List;
import java.util.Queue;public class ZigzagLevelOrder {public List<List<Integer>> zigzagLevelOrder(TreeNode root) {List<List<Integer>> res = new LinkedList<>();if (root == null) {return res;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);boolean flag = true; // 为 true 时从右边开始遍历,false 时从左边开始while (!queue.isEmpty()) {int size = queue.size();LinkedList<Integer> level = new LinkedList<>();for (int i = 0; i < size; i++) {TreeNode node = queue.poll();if (flag) {level.addLast(node.val);} else {level.addFirst(node.val);}if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}}flag = !flag;res.add(level);}return res;}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(N)

124. 二叉树中的最大路径和(⭐️⭐️)

思路

代码

class Solution {int res = Integer.MIN_VALUE;public int maxPathSum(TreeNode root) {traverse(root);return res;}// 返回当前节点能为父亲提供的贡献private int traverse(TreeNode root) {if (root == null) {return 0;}int left = traverse(root.left);int right = traverse(root.right);res = Math.max(res, root.val + left + right);int max = Math.max(root.val + left, root.val + right); // 计算当前节点能为父亲提供的最大贡献return max < 0 ? 0 : max;}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(log(N))

94. 二叉树的中序遍历(⭐️⭐️)

思路

中序遍历的过程中收集节点的值。

代码

import java.util.ArrayList;
import java.util.List;public class InorderTraversal {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();traverse(root, list);return list;}private void traverse(TreeNode root, List list) {if (root == null) {traverse(root.left, list);list.add(root.val);traverse(root.right, list);}}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(N)

199. 二叉树的右视图(⭐️⭐️)

思路

BFS每一层最后一个元素 or DFS 先访问每一层的右边的元素。

代码

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;public class RightSideView {private List<Integer> res = new ArrayList<>();public List<Integer> rightSideViewBFS(TreeNode root) {List<Integer> res = new ArrayList<>();if (root == null) {return res;}Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {int size = queue.size();for (int i = 0; i < size; i++) {TreeNode node = queue.poll();if (node.left != null) {queue.offer(node.left);}if (node.right != null) {queue.offer(node.right);}if (i == size - 1) {res.add(node.val);}}}return res;}public List<Integer> rightSideViewDFS(TreeNode root) {DFS(root, 0);return res;}private void DFS(TreeNode root, int depth) {if (root == null) {return;}if (depth == res.size()) {res.add(root.val);}depth++;DFS(root.right, depth);DFS(root.left, depth);}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:方法一:O(N),方法二:O(log(N))

105. 从前序与中序遍历序列构造二叉树(⭐️⭐️)

思路

代码

import java.util.HashMap;
import java.util.Map;public class BuildTree {private Map<Integer, Integer> map = new HashMap<>();public TreeNode buildTree(int[] preorder, int[] inorder) {for (int i = 0; i < inorder.length; i++) {map.put(inorder[i], i); // 记录中序序列每一个值的位置,用来划分左右子树的节点数量}return traverse(preorder, 0, preorder.length - 1,inorder, 0, inorder.length - 1);}private TreeNode traverse(int[] preorder, int preorderLeft, int preorderRight,int[] inorder, int inorderLeft, int inorderRight) {if (preorderLeft > preorderRight || inorderLeft > inorderRight) {return null;}int rootInInorderLocation = map.get(preorder[preorderLeft]);int sizeLeftSubtree = rootInInorderLocation - inorderLeft;TreeNode root = new TreeNode(preorder[preorderLeft]);root.left = traverse(preorder, preorderLeft + 1, preorderLeft + sizeLeftSubtree,inorder, inorderLeft, rootInInorderLocation - 1);root.right = traverse(preorder, preorderLeft + sizeLeftSubtree + 1, preorderRight,inorder, rootInInorderLocation + 1, inorderRight);return root;}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(log(N))

129. 求根节点到叶节点数字之和(⭐️⭐)

思路

DFS

代码

public class SumNumbers {public int sumNumbers(TreeNode root) {return DFS(root, 0);}private int DFS(TreeNode root, int preSum) {if (root == null) {return 0;}int sum = preSum * 10 + root.val;if (root.left == null && root.right == null) {return sum;} else {return DFS(root.left, sum) + DFS(root.right, sum);}}}

复杂度

  • 时间复杂度:
  • 空间复杂度:

104. 二叉树的最大深度(⭐️⭐️)

思路

后序遍历更新当前节点左右子树的最大深度。

代码

class Solution {public int maxDepth(TreeNode root) {if (root == null) {return 0;}int leftHeight = maxDepth(root.left);int rightHeight = maxDepth(root.right);return Math.max(leftHeight, rightHeight) + 1;}}

复杂度

  • 时间复杂度:O(N)
  • 空间复杂度:O(log(N))

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

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

相关文章

如何平衡冷数据(历史库)的成本与性能?| OceanBase应用实践

随着数据量的迅猛增长&#xff0c;企业和组织在数据库管理方面遭遇的挑战愈发凸显。数据库性能逐渐下滑、存储成本节节攀升&#xff0c;以及数据运维复杂性的增加&#xff0c;这些挑战使得DBA和开发者在数据管理上面临更大的压力。 为了应对这些挑战&#xff0c;对数据生命周期…

Jeecgboot3.6.3的vue3版本的一种flowable动态增加一个用户任务节点的方法(三)后端代码实现

因为这个项目license问题无法开源,更多技术支持与服务请加入我的知识星球。 这部分主要讲后端实现部分 1、增加一个AddTaskVo 类型,提供新增任务需要的数据结构 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.D…

C#使用Puppeteer

Puppeteer Puppeteer是一个Node.js库&#xff0c;它提供了高级API来通过DevTools协议(Chrome DevTools Protocol https://devtools.chrome.com)控制Chrome或Chromium。 Puppeteer默认情况下无头运行(headless)。 可以配置为运行完整的Chrome或Chromium&#xff0c;运行效果如…

spring02-springbean生命周期(实例化过程)

【README】 本文总结自《spring揭秘》&#xff0c;作者王福强&#xff0c;非常棒的一本书&#xff0c;墙裂推荐&#xff1b; spring容器根据配置元素组装可用系统分2个阶段&#xff0c;包括spring容器启动&#xff0c; springbean实例化阶段&#xff1b; 本文详细分析springbe…

单播---广播---组播

单播 单播&#xff08;Unicast&#xff09;是一种网络通信方式&#xff0c;其中数据包被发送到特定的网络接口。与广播&#xff08;Broadcast&#xff09;不同&#xff0c;单播只将数据包发送到目标地址指定的单个接收者。 单播的工作原理&#xff1a; 源地址&#xff1a;发…

DATAX自定义KafkaWriter

因为datax目前不支持写入数据到kafka中&#xff0c;因此本文主要介绍如何基于DataX自定义KafkaWriter&#xff0c;用来同步数据到kafka中。本文偏向实战&#xff0c;datax插件开发理论宝典请参考官方文档&#xff1a; https://github.com/alibaba/DataX/blob/master/dataxPlug…

240810-Gradio通过HTML组件打开本地文件+防止网页跳转到about:blank

A. 最终效果 B. 可通过鼠标点击打开文件&#xff0c;但会跳转到about:blank import gradio as gr import subprocessdef open_pptx():pptx_path /Users/liuguokai/Downloads/240528-工业大模型1.pptxtry:subprocess.Popen([open, pptx_path])return "PPTX file opened s…

【npm】如何将开发的vite插件发布到npm

前言 简单说下 npm 是什么&#xff1a; npm 是一个 node 模块管理工具&#xff0c;也是全球最大的共享源。 npm 工具与 nodejs 配套发布&#xff0c;便利开发人员共享代码。npm 主要包括 npm 官方网站、CLI&#xff08;控制台命令行工具&#xff09;、和 registry&#xff08;…

Python酷库之旅-第三方库Pandas(079)

目录 一、用法精讲 326、pandas.Series.str.normalize方法 326-1、语法 326-2、参数 326-3、功能 326-4、返回值 326-5、说明 326-6、用法 326-6-1、数据准备 326-6-2、代码示例 326-6-3、结果输出 327、pandas.Series.str.pad方法 327-1、语法 327-2、参数 327…

升级软文发稿开源系统源码论文期刊一键发布

升级软文发稿运营管理源码—论文期刊一键发布 软文发稿系统源码&#xff08;软文发布系统&#xff09;在基于旧版本的媒介软文发布平台项目改造升级了新的功能模块简称&#xff08;3.0版&#xff09;本系统还是基于开源的PHPMYSQLlayui&#xff08;前端界面&#xff09;代码进行…

Vue3使用ECharts的曲线条形堆叠混合图

先上效果图 图表容器 <div id"leftChart" style"height: 28vh"></div> <div id"rightChart" style"height: 28vh"></div> 监听resize视图窗口大小&#xff0c;可以让chart图表自适应大小 const leftChart …

wireshark使用介绍及案例分享

一、wireshark介绍 1、定义 wireshark是非常流行的网络封包分析软件,简称小鲨鱼,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。对应的,linux下的抓包工具是 tcpdump。 1.1、网络基础 参考TCP/IP五层模型,帧结构如下: 帧字段 帧字段含义 Frame 物理层的…

统计学第3天

P值 P值是原假设&#xff08;零假设&#xff09;H0为真的前提下&#xff0c;观察到的异常数据出现的概率。 如果P值很小&#xff0c;意味着原假设为真的情况下&#xff0c;取出能拒绝原假设数据的概率极低&#xff0c;此时取出了一个数据和原假设不符&#xff0c;说明了该组数…

ICMAN水位接近式检测方案(非接触式)

ICMAN水位液位接近式检测方案&#xff08;非接触式&#xff09; 我们的很多家用电器都会需要&#xff1a;液位检测 缺水&溢水提醒保护、高低液位提醒 液位传感器 像健康家电——烧水煮茶熬养生汤的烧水壶、豆浆机、养生壶等需要缺水保护和防溢液提醒&#xff1b; 像清洁…

DAMA学习笔记(十五)-数据管理组织与角色期望

1.引言 随着数据领域的快速发展&#xff0c;组织需要改进管理和治理数据的方式。当前&#xff0c;大多数组织正面临着越来越多的数据。这些数据格式多样、数量 庞大&#xff0c;并来源于不同的渠道。由于数据数量和种类的增加&#xff0c;加剧了数据 管理的复杂性。与此同时&am…

科研绘图系列:R语言多分组箱线图(grouped boxplot)

介绍 分组箱线图(Grouped Boxplot)是一种用于展示不同组别数据分布情况的统计图表。它将箱线图(Boxplot)按照不同的类别或组别进行分组,使得可以同时比较多个组别的数据特征。 箱线图本身是一种标准化的显示数据分布的方法,它能够展示数据的中位数、四分位数以及异常值…

【upload]-ini-[SUCTF 2019]CheckIn-笔记

上传图片木马文件后看到&#xff0c;检查的文件内容&#xff0c;包含<? 一句话木马提示 检查的文件格式 用如下图片木马&#xff0c;加上GIF89a绕过图片和<?检查 GIF89a <script languagephp>eval($_POST[cmd])</script> .user.ini实际上就是一个可以由用…

RAG与LLM原理及实践(11)--- Milvus hybrid search 源码分析及思想

目录 背景 hybrid search 源码分析 WeightedRanker 源码 hybrid search 核心 参数详解 基本入参 扩展入参 aysnc方式代码调用案例 说明 源码逻辑 prepare 调用过程 stub 调用结果 stub 调用过程 blocking 与 async 调用方式 深入内部core weightedRanker 的ch…

UCOSIII事件标志组详解

UCOSIII中的事件标志组是一种用于任务同步和事件管理的机制&#xff0c;它允许任务和中断服务例程&#xff08;ISR&#xff09;发布事件标志&#xff0c;并允许任务等待这些事件标志的发生。以下是对UCOSIII事件标志组的详细介绍&#xff1a; 1. 定义与创建 定义&#xff1a;…

软考:软件设计师 — 13.数据结构

十三. 数据结构 数据结构部分也可参考文章&#xff1a;Java数据结构知识点 — 5种常见数据结构 1. 线性结构 &#xff08;1&#xff09;线性表 顺序表 线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的数据元素&#xff0c;从而使得逻辑上相邻的两个元素…