110.平衡二叉树
题目
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
思路
递归法
本题既然要求比较高度,必然是要后序遍历
递归三部曲分析:
1.确定递归函数的参数和返回值
参数:当前传入节点。 返回值:以当前传入节点为根节点的树的高度。
那么如何标记左右子树是否差值大于1呢?
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。
2.明确终止条件
递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0
3.明确单层递归的逻辑
如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。
分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则返回-1,表示已经不是二叉平衡树了。
代码如下(JavaScript)
var isBalanced = function(root) {
//利用递归三部曲 + 后序遍历(左右中) 当前左右子树高度相差大于1就返回-1
//1.确定递归函数参数以及返回值
const getHeight =function(node){
//2.确定递归函数终止条件
if(node===null) return 0
//3.确定单层递归逻辑
let leftHeight =getHeight(node.left) //左子树高度
//当判定左子树不为平衡二叉树时,即可直接返回-1
if(leftHeight===-1)return-1
let rightHeight=getHeight(node.right) //右子树高度
//当判定右子树不为平衡二叉树时,即可直接返回-1
if(rightHeight===-1)return-1
if(Math.abs(leftHeight-rightHeight)>1){
return-1
}else{
return 1+Math.max(leftHeight,rightHeight)
}
}
return !(getHeight(root)===-1)
};
257. 二叉树的所有路径
题目
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
思路
这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。
前序遍历以及回溯的过程如图:
我们使用递归的方式,来做前序遍历。要知道递归和回溯就是一家的,本题也需要回溯。
递归法
1.递归函数参数以及返回值
参数:要传入的根节点,以及记录每一条路径的curPath
这里递归不需要返回值
2.确定递归终止条件
因为本题要找到叶子节点,就开始结束的处理逻辑了(把路径放进res里)。
那么什么时候算是找到了叶子节点? 是当 cur不为空,其左右孩子都为空的时候,就算找到叶子节点。
所以本题的终止条件是:node.left === null && node.right === null
3.确定单层递归逻辑
因为是前序遍历,需要先处理中间节点,中间节点就是我们要记录路径上的节点,先放进curPath中, curPath += node.val + '->'
然后是递归和回溯的过程,上面没有判断node是否为空,那么在这里递归的时候,就要判断如果为空就不进行下一层递归了。
所以递归前要加上判断语句,下面要递归的节点是否为空,如下:
node.left && getPath(node.left, curPath) //左
node.right && getPath(node.right, curPath) //右
代码如下(JavaScript)
这里的回溯隐藏在单层递归逻辑里面了。
var binaryTreePaths = function (root) {
//递归遍历+递归三部曲
const res = []
//1. 确定递归函数 函数参数
const getPath = function (node, curPath) {
//2. 确定终止条件,到叶子节点就终止
if (node.left === null && node.right === null) {
curPath += node.val
res.push(curPath)
return
}
//3. 确定单层递归逻辑
curPath += node.val + '->' //中
node.left && getPath(node.left, curPath) //左
node.right && getPath(node.right, curPath) //右
}
getPath(root, '')
return res
};
404.左叶子之和
题目
给定二叉树的根节点 root
,返回所有左叶子之和。
思路
首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。
因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:节点A的左孩子不为空,且左孩子的左右孩子都为空(说明是叶子节点),那么A节点的左孩子为左叶子节点
那么判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。
如果该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子,判断代码如下:
node.left !== null && node.left.left === null && node.left.right === null
递归法
递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和。
递归三部曲:
1.确定递归函数的参数和返回值
参数:判断一个树的左叶子节点之和,那么一定要传入树的根节点;
返回值:递归函数的返回值为数值之和,所以为整型数值
2.确定终止条件
如果遍历到空节点,那么左叶子值一定是0
if (node === null) return 0
注意,只有当前遍历的节点是父节点,才能判断其子节点是不是左叶子。 所以如果当前遍历的节 点是叶子节点,那其左叶子也必定是0,那么终止条件为:
if (node === null) return 0
if (node.left === null && node.right === null) return 0
3.确定单层递归逻辑
当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。
代码如下(JavaScript)
var sumOfLeftLeaves = function (root) {
//采用后序遍历 + 递归遍历
//1.确定递归函数参数
const nodesSum = function (node) {
//2.确定终止条件
if (node === null) return 0
if (node.left === null && node.right === null) return 0
//3.确定单层递归逻辑
let leftValue = nodesSum(node.left) //左
if (node.left !== null && node.left.left === null && node.left.right === null) { // 左子树就是一个左叶子的情况
leftValue = node.left.val
}
let rightValue = nodesSum(node.right) //右
let sum = leftValue + rightValue //中
return sum
}
return nodesSum(root)
};