110.平衡二叉树
题目链接:110. 平衡二叉树 - 力扣(LeetCode)
第一想法
直接递归
不过还是没想好递归的返回值怎么办
思路
需要分清楚节点的高度和深度,高度指的是和叶子节点的距离,深度指的是和根节点的距离
求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
递归三部曲:
-
明确递归函数的参数和返回值
参数是当前传入节点,返回值是以当前节点为根节点的树的高度
-
终止条件
空节点
-
单层递归逻辑
分别求节点的左右子树的高度,如果差值不大于1,则返回当前二叉树高度,否则,返回-1
function getHeight(node){
if(node == null){
return 0;
}
let left = getHeight(node.left);
if(left == -1) return -1;
let right = getHeight(node.right);
if(right == -1) return -1;
let height = Math.abs(left - right);
return height > 1 ? -1 : 1 + Math.max(left,right);
}
var isBalanced = function(root) {
let result = getHeight(root);
return result === -1 ? false : true;
};
这里返回比较巧妙,如果递归中发现不符合条件则直接返回-1,否则还是正常的返回二叉树的高度
最后再根据返回值来判断true 和 false
这一题的迭代法比较复杂,先跳过
总结
这题一开始没能理清楚递归每次要返回的值,本来想返回true 和 false,但是这两个无法在下一次中代入运算
实际上可以用一个专门的值来表示出现的某种情况,比如这里用-1来表示不满足条件的情况!!
257. 二叉树的所有路径
题目链接:257. 二叉树的所有路径 - 力扣(LeetCode)
第一想法
没有,写路径还是有点难
思路
这一题考验了递归和回溯的思想
递归三部曲:
-
确定递归函数的参数和返回值
这里参数是node,用来存储每次路径节点的数组curpath
返回最后的结果数组
-
确定终止条件
这里的终止条件应该是叶子节点,即左右子节点都为null
-
确定单层递归函数
这里用前序遍历(中左右)
即: curpath 添加当前节点的值和 ->
遍历左边
遍历右边
var binaryTreePaths = function(root) {
let res = [];
function getpath(node,curpath){
if(node.left == null && node.right == null){
curpath += node.val;
res.push(curpath);
return;
}
curpath += node.val + '->'
node.left && getpath(node.left,curpath);
node.right && getpath(node.right,curpath);
}
getpath(root,'');
return res;
};
这里有几个注意点:
- getpath是在binaryTreePaths中定义和使用的
- 终止条件中,直接return就好了,会自动回溯到上一个节点
- 最后一个节点后面不需要加 '->',所以在终止条件中有 curpath += node.val;
这题的迭代法其实还是用迭代来模拟递归,暂时先跳过去,二刷再看
总结
递归的回溯的细节其实隐藏在函数里面
想清楚递归的原理是栈,把图画出来理一理执行的逻辑就会清晰的多
404.左叶子之和
题目链接:404. 左叶子之和 - 力扣(LeetCode)
第一想法
后序遍历
把左节点的值相加
但是!!
这里是左叶子节点,不是左节点,所以并不行
思路
递归:
-
确定递归函数的参数和返回值
参数是node,返回值为节点数值之和
-
确定递归的终止条件
空节点,返回0
-
确定单层递归函数
这里使用后序(左右中)
求左子树的左叶子节点之和
求右子树的叶子节点之和
层层递归下去
var sumOfLeftLeaves = function(root) {
if(root == null) return 0;
let leftValue = sumOfLeftLeaves(root.left);
if(root.left && !root.left.left && !root.left.right){
leftValue = root.left.val;
}
let rightValue = sumOfLeftLeaves(root.right);
let sum = leftValue + rightValue;
return sum;
};
总结
这一题的思路之前并没有想到
遍历的过程还是比较巧妙的
把求左叶子节点的值的函数层层递归下去
每一层的返回值都是左叶子节点的和
并且需要通过父节点来判断是否是左叶子节点
这题的思路很巧妙,需要好好思考一下