算法打卡day15|二叉树篇04|110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

 算法题

Leetcode  110.平衡二叉树

题目链接:110.平衡二叉树

大佬视频讲解:平衡二叉树视频讲解

个人思路

可以用递归法,计算左右子树的高度差,当超过1时就不为平衡二叉树了;

解法

回顾一下二叉树节点的深度与高度;

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。

在leetcode中深度从1开始的,有些地方从0开始;

递归法

类似于二叉树的后序遍历,即对于当前遍历到的节点:先递归地判断其左右子树是否平
衡,
再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定
是非负整数),否则返回 -1。如果存在一棵子树不平衡,则整个二叉树一定不平衡。

如果是用前序遍历,则对于同一个节点,函数 getHeight 会被重复调用,导致时间复杂
度较高。如果使用后序遍历的做法,则对于每个节点,函数 height 只会被调用一次。

也可以这样记忆,当树节点高度与深度不同时,求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)

class Solution {public boolean isBalanced(TreeNode root) {//1.确定递归函数参数以及返回值return getHeight(root) != -1;//判断是否为平衡二叉树}private int getHeight(TreeNode root) {if (root == null) {//根;前序遍历,先遍历根;return 0;}//3.确定单层递归逻辑int leftHeight = getHeight(root.left);//左if (leftHeight == -1) {return -1;}int rightHeight = getHeight(root.right);//右if (rightHeight == -1) {return -1;}// 左右子树高度差大于1,return -1表示已经不是平衡树了if (Math.abs(leftHeight - rightHeight) > 1) {//2.确定递归终止条件return -1;}return Math.max(leftHeight, rightHeight) + 1;}
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(使用二叉树)

迭代法

来模拟后序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,其中利用TreeNode.val来保存当前结点的高度,这样就不会有重复遍历;

class Solution {public boolean isBalanced(TreeNode root) {if (root == null) {return true;}Stack<TreeNode> stack = new Stack<>();TreeNode pre = null;while (root != null || !stack.isEmpty()) {while (root != null) {stack.push(root);root = root.left;}TreeNode inNode = stack.peek();// 右结点为null或已经遍历过if (inNode.right == null || inNode.right == pre) {// 输出if (Math.abs(getHeight(inNode.left) - getHeight(inNode.right)) > 1) {return false;}stack.pop();pre = inNode;root = null;// 当前结点下,没有要遍历的结点了} else {root = inNode.right;// 右结点还没遍历,遍历右结点}}return true;}// 求结点的高度public int getHeight(TreeNode root) {if (root == null) {return 0;}int leftHeight = root.left != null ? root.left.val : 0;int rightHeight = root.right != null ? root.right.val : 0;int height = Math.max(leftHeight, rightHeight) + 1;root.val = height;// 用TreeNode.val来保存当前结点的高度return height;}
}

时间复杂度:O(n);(遍历整棵树)

空间复杂度:O(n);(一个栈的空间,最差情况下与树的空间一样,那就是n)


Leetcode 257. 二叉树的所有路径

题目链接:257. 二叉树的所有路径

大佬视频讲解:二叉树的所有路径视频讲解

个人思路

就知道好像是用回溯,但不记得怎么实现了

解法
递归法

要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径,因为要返回根到叶子结点的路径,所以肯定是需要回溯的,递归和回溯就是一家的;

因为是要记录到叶子节点的路径,所以左右孩子为空则为终止条件,到遍历到叶子节点,则将结果打印放入数组,然后回溯继续递归;

在写代码时,要记住回溯和递归是一一对应的,有一个递归,就要有一个回溯

class Solution {public List<String> binaryTreePaths(TreeNode root) {//1.确定递归函数参数以及返回值List<String> res = new ArrayList<>();// 存最终的结果if (root == null) {return res;}List<Integer> paths = new ArrayList<>();// 作为结果中的路径traversal(root, paths, res);return res;}private void traversal(TreeNode root, List<Integer> paths, List<String> res) {paths.add(root.val);// 前序遍历,中// 遇到叶子结点if (root.left == null && root.right == null) {//2.确定递归终止条件// 输出StringBuilder sb = new StringBuilder();// StringBuilder用来拼接字符串for (int i = 0; i < paths.size() - 1; i++) {sb.append(paths.get(i)).append("->");}sb.append(paths.get(paths.size() - 1));// 记录最后一个节点res.add(sb.toString());// 收集一个路径return;}//3.确定单层递归逻辑// 递归和回溯是同时进行,所以要放在同一个花括号里if (root.left != null) { // 左traversal(root.left, paths, res);//有一个递归,就要有一个回溯paths.remove(paths.size() - 1);// 回溯}if (root.right != null) { // 右traversal(root.right, paths, res);//有一个递归,就要有一个回溯paths.remove(paths.size() - 1);// 回溯}}
}

时间复杂度:O(n^2);(每遍历一条路径都要拷贝数据,高度乘节点,所以是n*n)

空间复杂度:O(n^2);(递归遍历暂存字符与结果,都需要空间)

迭代法

使用前序遍历的迭代方式来模拟遍历路径的过程


class Solution {public List<String> binaryTreePaths(TreeNode root) {List<String> result = new ArrayList<>();if (root == null)return result;Stack<Object> stack = new Stack<>();// 节点和路径同时入栈stack.push(root);stack.push(root.val + "");while (!stack.isEmpty()) {// 节点和路径同时出栈String path = (String) stack.pop();TreeNode node = (TreeNode) stack.pop();// 若找到叶子节点if (node.left == null && node.right == null) {result.add(path);}//右子节点不为空if (node.right != null) {stack.push(node.right);stack.push(path + "->" + node.right.val);}//左子节点不为空if (node.left != null) {stack.push(node.left);stack.push(path + "->" + node.left.val);}}return result;}
}

时间复杂度:O(n^2);(每遍历一条路径都要拷贝数据)

空间复杂度:O(n);(使用两个栈,一个存数据,一个遍历)


Leetcode 404.左叶子之和

题目链接:404.左叶子之和

大佬视频讲解:左叶子之和视频讲解

个人思路

可以用层序遍历,遍历到最后一层时,将左叶子筛选出来,结果值累加;

解法
递归法

递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。

递归三部曲

1.确定递归函数的参数和返回值

判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以为int

2.确定终止条件

如果遍历到空节点,那么左叶子值一定是0

注意,只有当前遍历的节点是父节点才能判断其子节点是不是左叶子。 所以如果当前遍历的节点是叶子节点,那其左叶子也必定是0:

3.确定单层递归的逻辑

当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。

class Solution {public int sumOfLeftLeaves(TreeNode root) {if (root == null) return 0;int leftValue = sumOfLeftLeaves(root.left);    // 左int rightValue = sumOfLeftLeaves(root.right);  // 右int midValue = 0;//判断是否为左叶子节点if (root.left != null && root.left.left == null && root.left.right == null) { midValue = root.left.val;}int sum = midValue + leftValue + rightValue;  // 中return sum;}
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(递归栈)

迭代法

层序遍历迭代法,采用前序遍历,在模板代码的基础上判断当前节点的子节点是否左叶子,并累加值;

class Solution {public int sumOfLeftLeaves(TreeNode root) {int sum = 0;//左叶子节点和if (root == null) return 0;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {int size = queue.size();while (size -- > 0) {TreeNode node = queue.poll();//判断是否为左叶子节点if (node.left != null) { // 左节点不为空queue.offer(node.left);if (node.left.left == null && node.left.right == null){ // 左叶子节点sum += node.left.val;}}if (node.right != null) queue.offer(node.right);}}return sum;}
}

时间复杂度:O(n);(遍历二叉树)

空间复杂度:O(n);(使用队列)

以上是个人的思考反思与总结,若只想根据系列题刷,参考卡哥的网址代码随想录算法官网代码随想录算法官网代码随想录算法官网

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

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

相关文章

Python学习:基础语法

版本查看 python --version编码 默认情况下&#xff0c;Python 3 源码文件以 UTF-8 编码&#xff0c;所有字符串都是 unicode 字符串。 特殊情况下&#xff0c;也可以为源码文件指定不同的编码&#xff1a; # -*- coding: cp-1252 -*-标识符 第一个字符必须是字母表中字母或…

rt-thread组件之audio组件(结合mp3player包使用)

前言 继上一篇RT-Thread组件之Audio框架i2s驱动的编写的编写&#xff0c;应用层使用rt-thread软件包里面的wavplayer组件以及 rt-thread组件之audio组件(结合wavplayer包使用)的文章本篇使用的是 mp3player软件包&#xff0c;与wavplayer设计框架基本上是一样的&#xff0c;只…

java-单列集合-set系列

set集合继承collection,所以API都差不多&#xff0c;我就不多加介绍 直接见图看他们的特点 我们主要讲述的是set系列里的HashSet、LinkedHashSet、TreeSet HashSet HashSet它的底层是哈希表 哈希表由数组集合红黑树组成 特点&#xff1a;增删改查都性能良好 哈希表具体是…

网络安全攻击数据的多维度可视化分析

简介 本研究项目通过应用多种数据处理与可视化技术&#xff0c;对网络安全攻击事件数据集进行了深度分析。首先&#xff0c;利用Pandas库读取并预处理数据&#xff0c;包括检查缺失值、剔除冗余信息以及将时间戳转化为日期时间格式以利于后续时间序列分析。 研究步骤 数据分析…

git commit --amend

git commit --amend 1. 修改已经输入的commit 1. 修改已经输入的commit 我已经输入了commit fix: 删除无用代码 然后现在表示不准确&#xff0c;然后我通过命令git commit --amend修改commit

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 2、线条平滑曲面但有间隔

环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata imp…

【李沐论文精读】GPT、GPT-2和GPT-3论文精读

论文&#xff1a; GPT&#xff1a;Improving Language Understanding by Generative Pre-Training GTP-2&#xff1a;Language Models are Unsupervised Multitask Learners GPT-3&#xff1a;Language Models are Few-Shot Learners 参考&#xff1a;GPT、GPT-2、GPT-3论文精读…

java基础2-常用API

常用API Math类 帮助我们进行数学计算的工具类。 里面的方法都是静态的。 3.常见方法如下&#xff1a; abs:获取绝对值 absExact:获取绝对值 ceil:向上取整 floor:向下取整 round:四舍五入 max:获取最大值 …

Stable Diffusion 模型:从噪声中生成逼真图像

你好&#xff0c;我是郭震 简介 Stable Diffusion 模型是一种生成式模型&#xff0c;可以从噪声中生成逼真的图像。它由 Google AI 研究人员于 2022 年提出&#xff0c;并迅速成为图像生成领域的热门模型。 数学基础 Stable Diffusion模型基于一种称为扩散概率模型(Diffusion P…

并查集算法

文章目录 并查集并查集引入1.初始化2.查询3.合并路径压缩代码模板(1)朴素并查集&#xff1a;(2)维护size的并查集&#xff1a;(3)维护到祖宗节点距离的并查集&#xff1a; 并查集 并查集引入 并查集&#xff08;Union-find Sets&#xff09;是一种非常精巧而实用的数据结构&a…

设计模式 -- 1:简单工厂模式

目录 代码记录代码部分 代码记录 设计模式的代码注意要运用到面向对象的思想 考虑到紧耦合和松耦合 把具体的操作类分开 不让其互相影响&#xff08;注意这点&#xff09; 下面是UML类图 代码部分 #include <iostream> #include <memory> // 引入智能指针的头文…

Redis底层核心对象RedisObject源码分析

文章目录 1. redis底层数据结构2. 插入KV底层源码流程分析 1. redis底层数据结构 redis 6数据结构和底层数据结构的关系 String类型本质是SDS动态字符串&#xff0c;即redis层面的数据结构底层会有对应的数据结构实现&#xff0c;上面是redis 6之前的实现 redis 7数据结构和底…

[MYSQL数据库]--表的增删查改和字段类型

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、表的增…

高数立体几何笔记

上个学期立体几何章节的一点笔记&#xff0c;很潦草&#xff0c;但重点内容基本都有复习到 Page1&#xff1a;介绍了向量的模、夹角、单位向量、投影投影向量、方向角、点乘、叉乘、混合积的基本运算和性质Page2: 回顾了高中所学的平面直线的多种表示方法以及距离的计算方法&…

【工作实践-07】uniapp关于单位rpx坑

问题&#xff1a;在浏览器页面退出登录按钮上“退出登录”字样消失&#xff0c;而在手机端页面正常;通过查看浏览器页面的HTML代码&#xff0c;发现有“退出登录”这几个字&#xff0c;只不过由于样式问题&#xff0c;这几个字被挤到看不见了。 样式代码中有一行为&#xff1a…

Midjourney绘图欣赏系列(十一)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子&#xff0c;它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同&#xff0c;Midjourney 是自筹资金且闭源的&#xff0c;因此确切了解其幕后内容尚不…

Linux常见指令总结

ls&#xff1a;显示当前目录下文件列表 常用的命令行参数&#xff1a; -l 显示更多的文件属性 -a 显示所有的文件/目录&#xff08;包括隐藏的&#xff09; -d 只显示目录 ps&#xff1a;参数可以叠加使用。 例如&#xff1a;ls -la 显示所有文件…

wait 和 notify方法

目录 1.1 wait()方法 wait 做的事情: wait 结束等待的条件: 1.2 notify()方法 1.3notifyAll方法 1.4wait()和sleep()对比 由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序. 完成这个协调…

重学SpringBoot3-日志Logging

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-日志Logging 引言默认日志配置日志门面如何实现默认配置 自定义日志配置日志级别日志分组日志格式日志输出自定义 Logback 配置切换日志框架 日志使用方…

数据结构 - 链表 (四)

这篇博客将介绍带头循环的双向链表&#xff0c;实现链表的头部插入/删除&#xff0c;尾部插入/删除&#xff0c;查找&#xff0c;以及任意位置的插入删除。 1.结构 带头循环的双向链表的结构如下图所示&#xff0c;一个结点内部包含数据&#xff0c;以及分别指向前一个以及后…