day17 | 110.平衡二叉树 257. 二叉树的所有路径 404.左叶子之和

文章详细介绍了三种二叉树问题的解决方案:110.平衡二叉树通过后序遍历检查左右子树高度差;257.二叉树的所有路径利用前序遍历获取所有路径;404.左叶子之和通过后序遍历计算左叶子节点的和。每部分都包含递归代码实现和逻辑分析。


110.平衡二叉树

1、代码(递归)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        //后序遍历
        int height = getHeight(root);
        if(height != -1){
            return true;
        }
        return false;
    }
    public int getHeight(TreeNode node){
        if(node == null){
            return 0;
        }
        //这里需要判断左右子树返回的都是-1的情况
        int leftHeight = getHeight(node.left);
        if(leftHeight == -1){
            return -1;
        }
        int rightHeight = getHeight(node.right);
        if(rightHeight == -1){
            return -1;
        }
        if(Math.abs(leftHeight - rightHeight) <= 1){
            //
            return Math.max(leftHeight,rightHeight) + 1;
        }else{
            return -1;
        }

    }
}

2、分析

(1)判断是否是平衡二叉树的依据是**“左右子树高度差绝对值不超过一”。**
(2)因为要求的是高度差,所以要返回左右子树的高度差给根节点,易得这是左右中的顺序,所以程序需要使用后序遍历。
(3)函数参数是根节点,返回值是高度,所以函数返回值为整型。
(4)后序遍历遍历到底部之后判断高度差的绝对值是否小于1,若小于1则记录其高度为1,返回上一层。上一层返回1+左右子树的最大高度,此为上一层的最终高度。
(5)代码:

        if(leftHeight == -1){
            return -1;
        }

这里需要对其单独判断的原因是当函数返回到根节点的时候,若左右子树都为-1,即左右子树都不满足平衡二叉树的定义,但是它们此时的高度差绝对值小于一,可以返回true。所以我们要对其加一个单独的判断,当左右子树的值为-1的时候,函数直接返回-1。
(6)本题需要返回布尔值,为什么要用-1,0来做返回值。因为我们在程序执行的时候需要用到整型变量来累计高度,此时可以使用一个小技巧来避免无法记录高度的情况:用-1表示false,0表示直接返回,其余数值表示我们需要用到的整型变量,到最后真正return的时候用表达式进行判断即可。

257. 二叉树的所有路径

1、代码(递归)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        //前序遍历
        List<String> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        List<Integer> paths = new ArrayList<>();
        dfs(root,paths,res);
        return res;
    }
    public void dfs(TreeNode node,List<Integer> paths,List<String> res){
        paths.add(node.val);
        if(node.left == null && node.right == null){
            //将路径加入到res
            StringBuilder sb = new 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;
        }
        if(node.left != null){
            dfs(node.left,paths,res);
            paths.remove(paths.size()-1);
        }
        if(node.right != null){
            dfs(node.right,paths,res);
            paths.remove(paths.size()-1);
        }
    }
}

2、分析

(1)这是递归回溯的题目,要回溯的原因是当函数走完一条路径时需要还原到初始时刻,所以我们需要在递归的时候用线性表在add之后进行remove,达到回溯的效果。
(2)如何寻找每一条不同的路径?
通过 if 判断节点的左和右节点是否为空,不为空则进行递归,按照前序遍历的顺序进行。

404.左叶子之和

1、代码(递归)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        //后序遍历
        if(root == null){
            return 0;
        }
        int res = dfs(root);
        return res;
    }
    public int dfs(TreeNode node){
        if(node == null){
            return 0;
        }
        //对叶子节点的先行判断,避免遍历叶子节点的左右空节点
        //因为本题借助叶子节点的上一个节点进行判断,所以可以在指针指向叶子节点的时候对其先行判断。
        if(node.left == null && node.right == null){
            return 0;
        }
        int value = 0;
        //对于左叶子节点的判断
        if(node.left != null && node.left.left == null 
            && node.left.right == null){
            value = node.left.val;
        }
        int leftValue = dfs(node.left);
        int rightValue = dfs(node.right);
        int res = value + leftValue + rightValue;
        return res;
    }
}

2、分析

(1)本题若直接对叶子节点进行操作,由于左右叶子的特性一致,导致无法判断是否为左叶子,所以我们可以借鉴操作链表的经验,直接操作左叶子的上一个节点。
(2)代码:

        if(node.left == null && node.right == null){
            return 0;
        }

这里对叶子节点进行先行判断后直接返回,可以直接减少一层递归循环。
(3)这里需要将左叶子节点的值进行相加,所以使用后序遍历将结果返回到根节点,所以每个函数的返回值都要相加并且最终返回到根节点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值