代码随想录训练营D17-二叉树篇 p4 | 110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和

迭代法,大家可以直接过,二刷有精力的时候 再去掌握迭代法。

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

再一次涉及到,什么是高度,什么是深度,可以巩固一下。

题目/文章/视频链接

深度:从根结点算起,力扣上规定根结点深度为1,也有规定根结点深度为0的。
高度:从叶子结点算起,叶子结点的高度为1,叶子结点下面的空结点高度为0.

求深度可以从上到下去查 所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中).

但 104.二叉树的最大深度 中求的是二叉树的最大深度,也用的是后序遍历。因为最大深度、最小深度,是与最大高度、最小高度相等的,所以可以使用后序遍历。

1. 思路

本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
由于本题涉及的是树的高度,高度是从下向上看的,从叶子结点算起,最后才算到根结点,所以采用后序遍历。

2. 代码

树中一个结点的左右子树绝对值超过1了,这个结点领导的树不是平衡二叉树了,那么上面的数也不是平衡二叉树了,所以此时返回-1

递归三部曲:
1.确定参数类型和返回值类型。参数类型:树结点;返回值,int 返回当前节点树的高度。递归过程中,任一结点不为平衡二叉树时,返回-1.
2.终止条件。遇到空结点时,返回高度0.
3.单层递归逻辑。
后序遍历,左右中。
先递归调用左子树,求左子树高度
再递归调用右子树,求右子树的高度
前面所求的子树高度若为-1,那么这里也直接返回-1
最后,求根,若左右子树高度差的绝对值 > 1,那么已经不是平衡二叉树了,返回-1。否则,还是平衡二叉树,此时应返回当前结点的高度 = 1 + max(左、右子树)

public boolean isBalanced(TreeNode root) {
	return getHeight(root) != -1;
}

//后序遍历
int getHeight(TreeNode node){
    if(node == null){
        return 0;
    }
    //左右根
    int left = getHeight(node.left);
    int right = getHeight(node.right);
    if(left == -1 || right == -1){
        return -1;
    }
    //根
    int minus = Math.abs(left - right);
    if(minus > 1){
        //差值绝对值大于1,则不是平衡二叉树
        return -1;
    }else {
        return 1 + Math.max(left, right);
    }
}

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

这是大家第一次接触到回溯的过程, 我在视频里重点讲解了 本题为什么要有回溯,已经回溯的过程。

如果对回溯 似懂非懂,没关系, 可以先有个印象。

题目/文章/视频链接

1. 思路

在这里插入图片描述
本题使用前序遍历。根左右:1253
125,遍历到叶子结点5时开始回溯,53弹出,此时剩1,继续遍历13
得到两条到叶子结点的路径125,13

若使用后序遍历。左右根:5231,无法得到125,13这两条路径
若使用中序遍历。左根右:2513,无法得到125,13这两条路径

因为我们要把路径记录下来,需要回溯来回退一个路径再进入另一个路径。
在这里插入图片描述
1)124到达叶子结点,先将当前路径124保存,再回溯到2
2)1257到达叶子结点,保存1257,回溯到5
3)1258,保存,回溯到1
4)136,保存,回溯到1

递归三部曲-函数名traversal
1)递归函数的参数及返回值。
这里是要保存所有路径,而不是计算高度深度等,所以这里不需要返回值,因此返回值是void。
参数:二叉树结点、当前路径的list-paths,以及最终组合上了‘->’的结果集list-res

2)确定终止条件。
因为这里要求的是到叶子结点的路径,所以到叶子结点就应该停止。
if(node.left == null && node.right == null)

3)单层递归逻辑
先序遍历–根左右

先将当前结点存在paths中。
遇到叶子节点,则代表当前路径已经找完,可以存到完善其形式并加入res中了。
接下来,就是继续先序遍历的‘左右遍历’
若左孩子不为null,则traversal左孩子,同时在递归下面紧接着回溯。
同理右孩子。

回溯和递归是一一对应的,有一个递归,就要有一个回溯。

2. 代码

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

//前序遍历(根左右)  递归 + 回溯
void traversal (TreeNode node, List<Integer> paths, List<String> res){
    //这里为什么对于根结点的处理要放在终止条件之前。若放在终止条件之后,则叶子结点不会被加到paths中。
    paths.add(node.val);

    //终止条件.若是叶子节点,直接将paths中数据组装好存到res中。
    if(node.left == null && node.right == null){
        StringBuilder sb = new StringBuilder();
        for(Integer num : paths){
            sb.append(num);
            sb.append("->");
        }
        sb.delete(sb.length() - 2, sb.length());
        res.add(sb.toString());
    }

    //左右
    //为什么这里不用先判断node是否为空?
    //因为首先在binaryTreePaths判断了首先进入的root一定不为空;
    //在traversal的前面遇到叶子结点就返回了,没有机会接触空结点。
    if(node.left != null){
        traversal(node.left, paths, res);//递归
        paths.remove(paths.size() - 1);//回溯
    }
    if(node.right != null){
        traversal(node.right, paths, res);//递归
        paths.remove(paths.size() - 1);//回溯
    }

}

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

其实本题有点文字游戏,搞清楚什么是左叶子,剩下的就是二叉树的基本操作。

题目/文章/视频链接

1. 思路

首先明确左叶子的定义:首先是叶子结点,并且是其父亲结点的左孩子。
本题的目的:计算这所有左叶子数值的和。
在这里插入图片描述

这种计算总和的二叉树的题目,都可以考虑是后序遍历。后序遍历,先左右,后根,刚好把左右子树的统计的和汇总到根结点处。

之前的一些二叉树题目都是在遍历到6时,判断一下这是不是我们需要的节点。而本题要在遍历到9时进行判断(条件是,当前节点9不为空,并且它的左孩子是叶子结点),这时这道题与其他题目的区别之处。

递归三部曲。
1)返回值int,参数二叉树结点
2)终止条件。为空结点时返回0,为叶子节点时,返回0
3)单层递归逻辑。
后序遍历。
若有左孩子。递归这个左孩子,存左侧 左叶子结点和 leftSum
若有右孩子,递归这个右孩子, 存右侧 左叶子结点和 rightSum

处理根节点。
若根节点,有左孩子且左孩子是叶子结点,存当前结点左叶子结点值
三数相加,返回

2. 代码

public int sumOfLeftLeaves(TreeNode root) {
    //用后序遍历
    //终止条件 空结点时、叶子结点时。
    // 因为现在判断是否要这个数的时机在左叶子的父结点那里
    if(root == null || (root.left == null && root.right == null)){
        return 0;
    }

    //左右根
    int leftSum = sumOfLeftLeaves(root.left);
    int rightSum = sumOfLeftLeaves(root.right);

    int midSum = 0;
    if(root.left != null && root.left.left == null && root.left.right == null){
        midSum = root.left.val;
    }
    return leftSum + rightSum + midSum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值