代码随想录算法训练营第十七天|二叉树part4

71 阅读3分钟

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;
};

总结

这一题的思路之前并没有想到

遍历的过程还是比较巧妙的

把求左叶子节点的值的函数层层递归下去

每一层的返回值都是左叶子节点的和

并且需要通过父节点来判断是否是左叶子节点

这题的思路很巧妙,需要好好思考一下