代码随想录算法训练营第15天 | 110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和、222.完全二叉树的节点个数

110.平衡二叉树 (优先掌握递归)

题目链接/文章讲解/视频讲解
再一次涉及到,什么是高度,什么是深度,可以巩固一下。

思路

  • 任何节点的左右子树高度差小于等于1则是平衡二叉树
  • 高度和深度:高度:到叶子节点的距离;深度:到根节点的距离。这道题求高度,就是后序遍历。

伪代码

//定义递归函数,参数和返回值
private int getHeight(TreeNode root){
    //终止条件  空节点高度为0
    if(node == null) return 0;  
    //发现任何一个节点不符合平衡二叉树的定义,直接返回-1
    //采用后序遍历  左右中
    int leftHeight = getHeight(root.left);  //左子树高度
    if(leftHeight == -1)  return -1;  //左子树高度==-1不符合平衡二叉树
    int rightHeight = getHeight(root.right);  //右子树高度
    if(rightHeight == -1) return -1;
    int result;
    //  一定要把中写在左右子树的后面,才能获取左右的情况返回给父节点
    if(Math.abs(leftHeight - rightHeight)  > 1){  //相减绝对值大于1  
        result = -1;
    }else{
      //  左右子树高度取最大值再加一
        result = Math.max(leftHeight, rightHeight) + 1;
    }
    return result;
}
/**
 * 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) {
        return getHeight(root) != -1;  //为什么这里要这么写
    }
    private int getHeight(TreeNode root){
        if(root == null) return 0;
        int leftHeight = getHeight(root.left);
        if(leftHeight == -1) return -1;
        int rightHeight = getHeight(root.right); 
        if(rightHeight == -1) return -1;
        return Math.abs(leftHeight - rightHeight) > 1 ? -1 : (Math.max(leftHeight, rightHeight) + 1);
    }
}

257. 二叉树的所有路径 (优先掌握递归)

题目链接/文章讲解/视频讲解

思路

  • 返回从根节点到叶子节点的所有路径
  • 使用前序遍历:这样才能让父节点指向孩子节点,才能把路径输出出来
  • 只要有递归就一定有回溯
    • 为什么会有回收的过程:一个容器来收集路径,怎么把一条路径收集完后,把子节点弹出去,重新回到根节点记录新路径呢?所以有回溯。

伪代码

//1. 定义函数,定义参数和返回值
// root 根节点; paths 记录单条路径的数组;res  记录最后结果,也是返回值
 private void traversal(TreeNode node, List<Integer> paths, List<String> res) {
//3. 前序遍历,中节点,因为遍历到叶子节点就结束了,所以要把叶子节点放进入才中止
paths.add(node.val);
//2. 确定终止条件:遍历到叶子节点
if(node.left == null && node.right == null){
    // 要把paths转化成String然后元素之间加上"->",代码略
    StringBuilder sb = new StringBuilder();// StringBuilder用来拼接字符串
    ……
    res.add(sb.toString())
    return;
  }
//向左递归
if(node != null){
    traversal(root.left, paths, res);
    paths.remove(paths.size() - 1);// 回溯,可以隐藏在参数中
}
//向右递归
if(node != null){
    traversal(root.right, paths, res);
    paths.remove(paths.size() - 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<>();// 作为结果中的路径
        traversal(root, paths, res);
        return res;
        
    }

    private void traversal(TreeNode root, List<Integer> paths, List<String> res){
        paths.add(root.val);
        if(root.left == null && root.right == null){
            StringBuilder s = new StringBuilder();
            for(int i = 0; i < paths.size()-1; i++){
                s.append(paths.get(i)).append("->");
            }
            s.append(paths.get(paths.size() - 1));
            res.add(s.toString());
            return;
        }
        if(root.left != null){
            traversal(root.left, paths, res);
            paths.remove(paths.size()-1);
        }
        if(root.right != null){
            traversal(root.right, paths, res);
            paths.remove(paths.size()-1);
        }
    }
}

404.左叶子之和 (优先掌握递归)

题目链接/文章讲解/视频讲解
其实本题有点文字游戏,搞清楚什么是左叶子,剩下的就是二叉树的基本操作。

思路

  • 左叶子节点的定义:一定是叶子节点(子节点为空);一定是父节点的左孩子。
  • 和之前二叉树题目的区别:无法判断叶子节点是不是父节点的左孩子,所以判断条件是:一个节点的左孩子不为空,同时左孩子的左右孩子都为空。
  • 使用后序遍历,因为要一层一层向上返回

伪代码

public int sumOfLeftLeaves(TreeNode root) {
    //终止条件
    if(root == null) return 0;
    if(root.left == null && root.right == null) return 0; // 不写也行,只是递归多了一层
    //单层递归的逻辑
    
    int leftNum = sumOfLeftLeaves(root.left);
    //左孩子不为空,同时左孩子为叶子节点
    if(root.left != null && root.left.left != null && root.right.right != null){
        leftNum = root.left.val;
    }
    int rightNum = sumOfLeftLeaves(root.right);
    int sum = leftNum + rightNum
    return sum; 
}
/**
 * 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;
        if (root.left == null && root.right == null) return 0;

        int leftValue = sumOfLeftLeaves(root.left);    // 左
        if (root.left != null && root.left.left == null && root.left.right == null) { // 左子树就是一个左叶子的情况
            leftValue = root.left.val;
        }
        int rightValue = sumOfLeftLeaves(root.right);  // 右

        int sum = leftValue + rightValue;               // 中
        return sum;
    }
}

222.完全二叉树的节点个数(优先掌握递归)

题目链接/文章讲解/视频讲解
需要了解,普通二叉树 怎么求,完全二叉树又怎么求

思路

  • 如果是普通的二叉树,就是遍历节点

后序遍历

class Solution {
    // 通用递归解法
    public int countNodes(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}
  • 利用完全二叉树的特性的写法
  • 完全二叉树的定义:除了底层节点每一层都是满的,底层节点都集中在该层最左边
  • 只要知道深度,节点数量就是2的深度次方 -1
  • 所以就是左子树的数量+右子树的数量+1
  • 如果是满二叉树,往左右两边遍历的深度相等;如果子树不相等则不是满二叉树,那么就继续向下递归,一定可以遇到符合满足条件的节点
public int countNodes(TreeNode root) {
//终止条件
        if (root == null) return 0;
        //遇到子树为满二叉树,也要返回结果并终止
        TreeNode left = root.left;
        TreeNode right = root.right;
        int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
        while (left != null) {  // 求左子树深度
            left = left.left;
            leftDepth++;
        }
        while (right != null) { // 求右子树深度
            right = right.right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容