代码随想录算法训练营第十五天| 层序遍历 、 226.翻转二叉树 、101. 对称二叉树

层序遍历 ⭐️

  • 题目链接:代码随想录

  • 关键点:

      1. 设置deep变量,既记录当前层数,也便于检查是否对数据第一次处理
      2. 每一层设置变量(len),根据这一层节点数,决定处理次数
  • 之前遍历二叉树都是深度优先遍历

  • 这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。

  • 层序遍历两种思路:
    ①迭代法(借助队列实现):
    每次遍历从队列中取出的元素的时候,如果其左右节点存在的话都将其添加到队列中
    遍历的终止条件时队列为空
    设置一个结果集和一个存放每一层元素的集合
    定义一个变量,存放每层遍历的长度

public List<List<Integer>> levelOrder(TreeNode root) {

    if(root == null){
        return new ArrayList<List<Integer>>();
    }

    Deque<TreeNode> deque = new LinkedList<>();
    List<List<Integer>> res = new ArrayList<>();

    deque.addLast(root);

    while(!deque.isEmpty()){

        List<Integer> tempList = new ArrayList<>();
        //每一层元素的多少
        int len = deque.size();

        //每一层遍历
        while((len--) > 0){
            TreeNode treeNode = deque.removeFirst();
            tempList.add(treeNode.val);

            if(treeNode.left != null){
                deque.addLast(treeNode.left);
            }
            if(treeNode.right != null){
                deque.addLast(treeNode.right);
            }
        }
        //每一层结束之后,添加元素
        res.add(tempList);

    }

    return res;

}
  • 解题思路:(DFS)
    ①设置一个变量deep来决定每层的深度,用于判断该层是否创建数组和存放元素
    ②每递归一层,深度+1
    ③根据结果集当前长度决定是否创建新的层数结果集
    ④逻辑处理:每次为当前层数的结果集添加元素,这样即使先遍历左边元素,也
    保证最终返回的结果集的顺序
public void checkFun01(TreeNode node, Integer deep) {
    List<List<Integer>> resList = new ArrayList<List<Integer>>();

    if (node == null) return;
    deep++;

    //决定是否该层创建数组
    if (resList.size() < deep) {
        //当层级增加时,list的Item也增加,利用list的索引值进行层级界定
        List<Integer> item = new ArrayList<Integer>();
        resList.add(item);
    }
    //有效做到了分层
    resList.get(deep - 1).add(node.val);

    //层序遍历左边部分
    checkFun01(node.left, deep);
    //层序遍历右边部分
    checkFun01(node.right, deep);
}

226.翻转二叉树

题目链接:代码随想录

  • 解题思路:
    ①参数:传入每次要处理的节点
    ②处理逻辑:每次交换传入节点的左右节点,做到互换位置
    ③返回值为空

  • 前后序遍历都可以
    中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),
    再右孩子交换孩子(此时其实是对原来的左孩子做交换)

public TreeNode invertTree(TreeNode root) {
    treeReverse(root);
    return root;
}

public void treeReverse(TreeNode root){

    if(root == null){
        return;
    }

    //交换节点
    TreeNode tempNode = null;
    tempNode = root.left;
    root.left = root.right;
    root.right = tempNode;

    treeReverse(root.left);
    treeReverse(root.right);

}

101. 对称二叉树⭐️

在这里插入图片描述

题目链接:代码随想录

  • 解题思路:

    ​ 本题采用后序遍历,因为只有这样才能在收集完左右孩子信息后返回做出比较

  • 具体三步:(参考代码随想录分析)

    1. 确定递归函数的参数和返回值

      因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点,返回值为boolean类型

    2. 确定终止条件

      节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点

      • 左节点为空,右节点不为空,不对称,return false
      • 左不为空,右为空,不对称 return false
      • 左右都为空,对称,返回true

      此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:

      • 左右都不为空,比较节点数值,不相同就return false(这里一定要先比较不相同的情况,一旦左右不相同直接告诉根节点不匹配就可以了)

      此时左右节点不为空,且数值也不相同的情况我们也处理了。

    3. 确定单层递归的逻辑

      此时才进入单层递归的逻辑,只有在处理左右节点都不为空,且数值相同的情况,才进入单层递归逻辑(理解这一点很重要)

      • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
      • 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
      • 如果左右都对称就返回true ,有一侧不对称就返回false 。
    4. 定性分析

      我们可以看出使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)。

public boolean isSymmetric(TreeNode root) {
    return compare(root.left,root.right);
}

private boolean compare(TreeNode left,TreeNode right){


    if(left == null && right != null){
        return false;
    }

    if(left != null && right == null){
        return false;
    }

    if(left == null && right == null){
        return true;
    }
    //上面防止了下面的空指针异常
    //这一步一定是判断数值不相等的情况
    if(left.val != right.val){
        return false;
    }

    // 此时就是:左右节点都不为空,且数值相同的情况
    // 此时才做递归,做下一层的判断
    //比较外侧的值
    boolean compareOut = compare(left.left, right.right);
    //比较内侧的值
    boolean compareIn = compare(left.right, right.left);

    return compareOut && compareIn;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值