算法打卡day15|二叉树篇04|Leetcode 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);(递归树的高度h)

迭代法

来模拟后序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合,其中利用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);(递归树的高度h)

迭代法

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

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://xiahunao.cn/news/2871623.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

旧华硕电脑开机非常慢 电脑开机黑屏很久才显示品牌logo导致整体开机速度非常的慢怎么办

前提条件 电池需要20&#xff05;&#xff08;就是电池没有报废&#xff09;且电脑接好电源&#xff0c;千万别断电&#xff0c;电脑会变成砖头的 解决办法 更新bios即可解决&#xff0c;去对应品牌官网下载最新的bios版本就行了 网上都是一些更新驱动啊

leetcode代码记录(每日温度

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如…

Docker 哲学 - 容器操作 -cp

1、拷贝 容器绑定的 volume的 数据&#xff0c;到指定目录 2、匿名挂载 volume 只定义一个数据咋在容器内的path&#xff0c;docker自动生成一个 sha256 的key作为 volume 名字。这个 sha256 跟 commitID 一致都是唯一的所以 &#xff0c;docker利用这个机制&#xff0c;可以…

5分钟教你激活喀秋莎Camtasia2023中文破解Crack下载附安装教程

Camtasia2023又称喀秋莎2023&#xff0c;集屏幕录制和视频剪辑功能于一体的软件&#xff0c;提供屏幕录制、区域录制、摄像头录制等多种录制方式&#xff0c;Camtasia2023版本带来了新的动态背景库、霓虹光标图像、录制语音旁白等多种新功能&#xff0c;适用于游戏录制、课程录…

ISIS接口MD5 算法认证实验简述

默认情况下&#xff0c;ISIS接口认证通过在ISIS协议数据单元&#xff08;PDU&#xff09;中添加认证字段&#xff0c;例如&#xff1a;MD5 算法&#xff0c;用于验证发送方的身份。 ISIS接口认证防止未经授权的设备加入到网络中&#xff0c;并确保邻居之间的通信是可信的。它可…

springboot使用socket和端口启动gRPC服务器的比较

gRPC 服务器启动方式比较 一. 介绍二. 套接字地址方式三. 端口方式四. 如何选择 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一. 介绍 百度百科套接字 gRPC 是一种高性能的远…

《手把手教你》系列技巧篇(三十八)-java+ selenium自动化测试-日历时间控件-下篇(详解教程)

1.简介 理想很丰满现实很骨感&#xff0c;在应用selenium实现web自动化时&#xff0c;经常会遇到处理日期控件点击问题&#xff0c;手工很简单&#xff0c;可以一个个点击日期控件选择需要的日期&#xff0c;但自动化执行过程中&#xff0c;完全复制手工这样的操作就有点难了。…

C++根据三点求平行四边形的平分阵列

C根据三点求平行四边形的平分阵列 如下图&#xff0c;已知ABC三个点&#xff0c;且ABCD是平行四边形&#xff0c;求各个点的(阵列)的坐标 void OnBnClickedButtonCreatematrix3point() {//通过前面三点&#xff0c;计算出第四点POINTF64 t_pointMiddle;//对角线交点t_pointMi…

iOS常见崩溃简介

1. 崩溃 多指在移动设备&#xff08;如iOS、Android设备&#xff09;中或不可移动设备&#xff08;如:Windows、Linux等设备&#xff09;&#xff0c; 在打开或使用应用程序时出现的突然退出中断的情况&#xff08;类似于Windows的应用程序崩溃&#xff09;。 多表现为&#…

关于IP-Adapter的十几个模型,到底是干啥用的?

&#x1f3a0;背景介绍 IP-Adapter的一系列模型在stable diffusion的实际应用中&#xff0c;越来越被频繁的使用到&#xff0c;用于“换脸”或者“保证角色的一致性”&#xff0c;但是很多朋友在安装或者使用别人的工作流的时候&#xff0c;经常会遇到各种各样的问题&#xff…

考研数二要掌握的初中知识点

文章目录 一、整式1. 同底数幂的乘法2. 幂的乘方3. 积的乘方4. 乘法分配律5. 同底数幂的除法 二、分式1. 分式的乘法2. 分式的除法3. 分式的乘方4. 分式的最简公分母5. 负指数幂6. 比例变形7. 分离常数法 三、二次根式0. 平方根和算数平方根的重要概念1. 乘方去根号2. 二次根式…

118. 杨辉三角(Java)

这里写目录标题 题目描述&#xff1a;输入:输出:代码实现&#xff1a; 题目描述&#xff1a; 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 输入: numRows 5输出: [[1],[1,1],[1…

考研数学|武忠祥各阶段搭配用书汇总

看到有人问武忠祥老师&#xff0c;不请自来 武忠祥老师&#xff0c;绝对的宝藏老师&#xff0c;我在考研强化阶段的时候听过他的强化课程&#xff0c;听完之后&#xff0c;很多问题都想通了&#xff0c;所以&#xff0c;如果有人想问武忠祥老师行不行&#xff0c;那我就一个字…

19. UE5 RPG使用GameplayEffect的Attribute Based Modifiers

前几篇文章我也说了GE的基础使用&#xff0c;但是&#xff0c;对一些属性的应用没有述说&#xff0c;后续&#xff0c;我将一点一点的将它们如何使用书写下来。 这一篇&#xff0c;主要就讲解一下Attribute Based Modifiers使用&#xff0c;先说一下它的应用场景&#xff0c;一…

数据结构——栈和队列的表示与实现详解

目录 1.栈的定义与特点 2.队列的定义与特点 3.案例引入 4.栈的表示和操作的实现 1.顺序栈的表示 代码示例&#xff1a; 2.顺序栈的初始化 代码示例&#xff1a; 3.判断栈是否为空 代码示例&#xff1a; 4.求顺序栈长度 代码示例&#xff1a; 5.清空顺序栈 …

Spring Boot中application配置文件的生效顺序

Spring Boot的一个重要特性就是它的自动配置&#xff0c;这一特性在很大程度上依赖于名称为application的配置文件。本文将详细介绍在Spring Boot中&#xff0c;这些配置文件的加载顺序以及每份文件的应用范围。 文章目录 配置文件的种类配置文件的加载顺序配置文件的环境切换 …

操作系统内功篇:硬件结构之CPU缓存一致性

一 CPU Cache的数据写入 1.1 CPU Cache的结构 是由很多个Cache Line组成的&#xff0c;CPU Line是CPU从内存读取的基本单位&#xff0c;CPU Line是由多个标志数据块组成。 1.2 CPU Cache数据的写入 数据不仅仅只有读取&#xff0c;还有数据的写入&#xff0c;写入数据也是先…

【智能算法】斑鬣狗优化算法(SHO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过。 3.代码实现4.参考文献 1.背景 2017年&#xff0c;Dhiman等人受到斑鬣狗自然狩猎行为启发&#xff0c;提出了斑鬣狗优化算法(Spotted Hyena Optimizer, SHO)。 2.算法原理 2.1算法思想 SHO将斑鬣狗狩猎行为分为围捕-狩猎-进攻三…

JVM实战篇

内存调优 内存溢出和内存泄漏 内存泄漏&#xff1a;在java中如果不再使用一个对象&#xff0c;但是该对象依然在GC ROOT的引用链上&#xff0c;这个对象就不会被垃圾回收器回收。 内存泄漏绝大多数情况都是由堆内存泄漏引起的&#xff0c;所以后续没有特别说明则讨论的都是堆…

matplotlib画堆叠、并列直方图

在用 matplotlib.pyplot.hist 画分布图时&#xff0c;若总分布由几个分量组成&#xff08;如高斯混合&#xff09;&#xff0c;想用不同颜色标识出来&#xff0c;方便看到各分量占比&#xff0c;参考 [1]。 效果&#xff1a; 分布由两个分量&#xff08;x、y&#xff09;组成…