二叉树相关题目练习-代码随想录

110.平衡二叉树

题目链接/文章讲解/视频讲解:https://programmercarl.com/0110.%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91.html

题目分析:平衡二叉树就是所有节点的左右子树高度差不超过1的二叉树

那么既然是求高度那么就得知道高度从叶子节点开始是从下向上计算,而深度是根节点开始从上向下计算
在这里插入图片描述

既然知道是从下向上来计算高度后,我们就可以想到二叉树的遍历顺序一定会是后序遍历

因为只有处理了左右子树的高度后,我们才能知道当前节点的高度

例如:图中的节点3,我只有知道节点3的左右孩子都是null后,我才能知道节点3的高度为1

public boolean isBalanced(TreeNode root) {
    int res = getHigh(root);
    return res==-1 ? false:true;
}

public int getHigh(TreeNode node){
    // 如果当前节点为空,则表示高度为0
    if(node == null) return 0;

    // 遍历子树高度
    // 这里一定要注意遍历的顺序,求高度,那么就是从下向上计算,使用的就是后序
    // 因为是从下向上所以就得计算出左右子树的高度,再处理中间节点(父节点)
    int leftHigh = getHigh(node.left);
    if(leftHigh == -1) return -1;
    int rightHigh = getHigh(node.right);
    if(rightHigh == -1) return -1;

    int res;
    // 如果左右子树的高度的绝对值大于1,就表示整个树不是平衡二叉树
    if(Math.abs(leftHigh-rightHigh) > 1) res = -1;
    // 如果高度差不大于1,那么我就返回高度较高的子树的高再+1,计算当前节点的高度
    //    1
    //  2    3
    //         4
    // 这里就可以看出,左子树高度:1,右子树高度:2
    // 同时相减后高度差也小于1
    // 那么节点1的高度就是:较高的子树+1 = 当前节点高度
    // 同时也表示当前节点是一个平衡二叉树
    else res = 1+Math.max(leftHigh,rightHigh);

    return res;
}

257.二叉树的所有路径

题目链接/文章讲解/视频讲解:https://programmercarl.com/0257.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%89%80%E6%9C%89%E8%B7%AF%E5%BE%84.html

在这里插入图片描述

本题要就需要使用到回溯,上图中所有的路径[“1-2-5”,“1-3”]

  • 首先存储我们遍历过的节点,当我们遍历到叶子节点时就需要开始回退
  • 把5,2弹出,这个步骤就是回溯,为什么需要弹出?因为只有弹出5,2我们才能回到节点1,这样才能找到节点3,记录下一条路径
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;
}


public void traversal(TreeNode node, List<Integer> paths, List<String> res){
    // 提前存储遍历的路径,避免叶子节点被if提前返回而没有存储
    paths.add(node.val);
    // 终止条件:当前节点是否为叶子节点
    if(node.left==null && node.right==null){
        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){
        traversal(node.left,paths,res);
        // 回溯
        // 因为paths中已经记录我们当前遍历的路径
        // 例如:当前路径:1-2-3-4 ,下一条路径是:1-2-3-5
        // 那么我们就需要回退到3这个节点,才能去收集下一条路径
        paths.remove(paths.size()-1);
    }
	// 注意回溯和递归是一一对应的,有一个递归就得有一个回溯
    if(node.right!=null){
        traversal(node.right,paths,res);
        // 回溯
        paths.remove(paths.size()-1);
    }
}

404.左叶子之和

题目链接/文章讲解/视频讲解:https://programmercarl.com/0404.%E5%B7%A6%E5%8F%B6%E5%AD%90%E4%B9%8B%E5%92%8C.html

在这里插入图片描述

题目分析:首先我们就得先知道什么是左叶子,举例:节点A的左孩子B如果是叶子节点那么B就是左叶子

上图中的左叶子就只有9、15,例子中我们就可以知道要知道当前节点是不是左叶子,那么我们就得根据当前节点的父节点来判断 if(root.left!=null && root.left.leftnull && root.left.rightnull) 那么就是只有满足这个条件的节点,我们才取出值来进行相加

public int sumOfLeftLeaves(TreeNode root) {
    // 递归法
    if(root==null) return 0;
    // 如果当前节点为叶子节点也可以退出
    if(root.left==null && root.right==null) return 0;

    int leftNum = sumOfLeftLeaves(root.left);
    // 节点A的左孩子节点不为空 且 左孩子还是叶子节点
    // 那么节点A的左孩子节点就是左叶子,记录左孩子的值
    if(root.left!=null && root.left.left==null && root.left.right==null)
        leftNum = root.left.val;

    int rightNum = sumOfLeftLeaves(root.right);

    int sum = leftNum + rightNum;
    return sum;



    // 迭代法:层序遍历
    Queue<TreeNode> q = new LinkedList<>();
    int res=0;
    q.add(root);
    while(!q.isEmpty()){
        int size = q.size();
        while(size!=0){
            TreeNode cur = q.poll();
            if(cur.left!=null && cur.left.left==null && cur.left.right==null){
                res += cur.left.val;
            }
            if(cur.left!=null) q.add(cur.left);
            if(cur.right!=null) q.add(cur.right);
            size--;
        }
    }
    return res;
}

222.完全二叉树的节点个数

题目链接/文章讲解/视频讲解:https://programmercarl.com/0222.%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%8A%82%E7%82%B9%E4%B8%AA%E6%95%B0.html

// 普通解法
public int countNodes(TreeNode root) {
    if(root == null){
        return 0;
    }

    return countNodes(root.left)+countNodes(root.right)+1;
}

// 利用完全二叉树的特性
public int countNodes(TreeNode root) {
    return getNum(root);
}

public int getNum(TreeNode node){
    // 终止条件不仅要判断为空,还要判断是否为满二叉树
    if(node == null ) return 0;
    TreeNode left = node.left;
    TreeNode right = node.right;
    // 计算左右子树的深度从1开始
    int leftCount=1,rightCount=1;
    while(left!=null){
        left = left.left;
        leftCount++;
    }
    while(right!=null){
        right = right.right;
        rightCount++;
    }
    // 满二叉树求节点的公式:2^n-1(n:深度)
    // 因为题目要求这个二叉树是完全二叉树
    // 所以只要当前节点的左右子树的深度相同,那么就是满二叉树
    if(leftCount==rightCount) return (2<<(leftCount-1))-1;

    int leftNum = getNum(node.left);
    int rightNum = getNum(node.right);
    return leftNum+rightNum+1;
}

前节点的左右子树的深度相同,那么就是满二叉树
if(leftCount==rightCount) return (2<<(leftCount-1))-1;

int leftNum = getNum(node.left);
int rightNum = getNum(node.right);
return leftNum+rightNum+1;

}


  • 16
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值