Day 17
01. 平衡二叉树(No. 110)
题目链接
代码随想录题解
1.1 题目
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:true
示例 2:
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
示例 3:
输入:root = []
输出:true
提示:
- 树中的节点数在范围
[0, 5000]
内 -104 <= Node.val <= 104
1.2 笔记
首先来回顾高度和深度的区别,先用这张图来描述节点的深度
接下来将其改造为展示高度的图像
高度和深度为 1
的位置是不同的,注意不是完全相反,高度为 1
的位置是所有没有子节点的位置,而深度为 1
的位置则一定是头节点(if not null
),这也就使得求高度和深度的计算位置有所不同。
深度是以上个节点为根基进行自增,而高度则需要以子节点为根基,一个节点的高度是 其左节点和右节点高度的最大值。
所以求深度使用前序遍历,求高度使用后序遍历
在写递归之前先来看递归之前要考虑的三个部分:
- 递归的出口:本题中的出口是
node == null
也就是遍历到最后一个节点的时候 - 递归的返回值:因为要拿取到子节点的深度,这里返回值定为
int
为该节点的深度 - 递归中要进行的步骤:遍历左节点求得高度、遍历右节点求得高度,取高度的最大值再加一
和之前提到的一样,不要在脑中取执行递归,脑子存不下几个栈的,这种存储的行为交给计算机去做,我们需要做的是想出上面的三个部分,以这个题为例,递归出口很好想出,接下来确定返回值,确定了是 深度。
深度的逻辑是什么呢?
是左节点和右节点深度和的最大值。
那左节点和右节点的深度如何计算呢?
通过递归
想到这里就可以写出代码了,至于左节点右节点怎么计算,就是计算机执行的内容了,我们只负责 单层逻辑 的处理。
有了深度只需要在每次返回前判断左右子树的高度即可看出是否是平衡二叉树
1.3 代码
class Solution {// 最终的返回值boolean flg = true;public boolean isBalanced(TreeNode root) {reverse(root);return flg;}public int reverse(TreeNode node) {if (node == null) {return 0;}int rightNum = reverse(node.right);int leftNum = reverse(node.left);// 判断是否平衡if (rightNum - leftNum > 1 || leftNum - rightNum > 1) {flg = false;}return Math.max(rightNum, leftNum) + 1;}
}
02. 二叉树的所有路径(No. 257)
题目链接
代码随想录题解
2.1 题目
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3,null,5]
输出:[“1->2->5”,“1->3”]
示例 2:
输入:root = [1]
输出:[“1”]
提示:
- 树中节点的数目在范围
[1, 100]
内 -100 <= Node.val <= 100
2.2 笔记
代码随想录刷题笔记 DAY16 | 二叉树的最大深度 No.104 | 二叉树的最小深度 No.111 | 完全二叉树的节点个数 No.222
这道题和昨天的二叉树的最小深度很像,都有判断叶子节点的步骤,叶子节点就是返回结果的位置,从头节点开始,通过 path
来记录通过的路径,在离开节点的时候弹出当前节点的记录即可实现路径的遍历。
最后将 path
转为需要的格式返回即可
再次回顾递归的三个步骤
-
确认递归的出口,本题有两个出口,第一个是
node == null
也就是遍历到空节点的时候,但空节点并非一定是叶子节点,比如下图
如果仅仅通过
node == null
来判断,这些节点的上一个节点都会被判定为叶子节点,也就是1
2
3
节点均会判定为叶子节点,所以还需要限制left == null
和right == null
这才能准确的定位到3
节点。 -
递归的返回值:使用
path
来收集信息,直接return
即可,返回值为空 -
每层递归的逻辑:(前序位置:判断条件、记录当前路径)、(遍历左节点、遍历右节点)、(后序位置:弹出节点的值)
2.3 代码
class Solution {List<String> res = new ArrayList<String>(); // 返回的结果List<String> path = new ArrayList<String>(); // 收集路径信息public List<String> binaryTreePaths(TreeNode root) {reverse(root);return res;}public void reverse(TreeNode node) {// 前序位置if (node == null) {return;}path.add(String.valueOf(node.val));// 判断是否是叶子节点if (node.right == null && node.left == null) {String resString = getResString(path);res.add(resString);path.remove(path.size() - 1);return;}reverse(node.left);reverse(node.right);// 后序位置,离开节点时弹出path.remove(path.size() - 1);}/*将 path 转为需要的结果的方法*/public String getResString(List<String> path) {String resString = "";for (int i = 0; i < path.size() - 1; i++) {resString += path.get(i) + "->";}resString += path.get(path.size() - 1);return resString;}
}
03. 左叶子之和(No. 404)
题目链接
代码随想录题解
3.1 题目
-
给定二叉树的根节点
root
,返回所有左叶子之和。示例 1:
输入: root = [3,9,20,null,null,15,7]
输出: 24
解释: 在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24示例 2:
输入: root = [1]
输出: 0提示:
- 节点数在
[1, 1000]
范围内 -1000 <= Node.val <= 1000
- 节点数在
3.2 笔记
这道题首先要搞懂左叶子是哪个位置,来看下面这张图
如果问这张图的左叶子之和很有可能会得到两个结果,9 + 3 + 15 = 27
和 3 + 15 = 18
,凭字面理解,很明显是第二个对了,因为要找的是 左叶子节点 而非 左分支节点,所以和上题一样,要加判断是否为叶子节点的代码,我认为这题很适合作为递归的一个例题,因为本题的递归三步法比较复杂。
先来确认遍历顺序,本题要收集叶子节点也就是子节点的情况,所以使用 后序遍历
同样的,来确认三个部分
- 递归的出口:
node == null
这是毋庸置疑的,因为对空节点的任何操作都没有意义 - 递归的返回值,返回节点的 左叶子 的值,因为如果在一个节点内部,是很难判断是左叶子还是右叶子的,所以要交给上一级节点取判断。
- 递归中执行的内容:(前序位置:检查是否为空节点、拿取节点左叶子的值(
if not null
))、(遍历左节点、遍历右节点)、(后续位置:返回当前节点以下所有 左叶子 的值)
这里再稍微提及一下如何判断叶子节点:首先它自己不能为空,同时左右节点都为空,但本题是交给上个节点取判断的,就从下面的代码变成了
if (node != null && node.right == null && node.left == null) {temp = node.val;
}
if (node.left != null && node.left.right == null && node.left.left == null) {temp = node.left.val;
}
写出代码
3.3 代码
class Solution {public int sumOfLeftLeaves(TreeNode root) {return reverse(root);}public int reverse(TreeNode node) {int temp = 0;if (node == null) {return 0;}// 判断左叶子if (node.left != null && node.left.right == null && node.left.left == null) {// 当前节点的左叶子的值(如果存在的话),注意是左叶子temp = node.left.val;}int leftNum = reverse(node.left);int rightNum = reverse(node.right);return leftNum + rightNum + temp;}
}