力扣刷题之二叉树(2) | 层序遍历、226. 翻转二叉树、101. 对称二叉树

层序遍历

Leetcode 102. 二叉树的层序遍历

题目链接

思路

层序遍历就是从左到右、一层一层去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样,需要借用一个辅助数据结构即队列来实现,队列(先进先出),符合一层一层遍历的逻辑,而用栈(先进后出) 适合模拟深度优先遍历,也就是递归的逻辑

使用队列实现二叉树广度优先遍历,动画如下:
在这里插入图片描述

难点

这道题的关键在于,要按层来输出,即,每层的节点要放进一个list里
所以如何来定位每层?其实就是计算出队前队列里一共有多少个节点,这些节点都是同一层的。因为我们在入队每一个节点的子节点时,已经将父节点出队了。
这个队列的长度要提前计算,因为后面入队出队时,队列长度会有变化。

代码(Java)

写法1:迭代法

时间复杂度: O(n)
空间复杂度: O(n)

/**
 * 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<List<Integer>> levelOrder(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if (root == null)
            return res;
        queue.offer(root);

        while (!queue.isEmpty()){
            List<Integer> itemList = new ArrayList<>();
            int len = queue.size();
            while (len>0){
                TreeNode tempNode = queue.poll();
                itemList.add(tempNode.val);
                if (tempNode.left != null)
                    queue.offer(tempNode.left);
                if (tempNode.right != null)
                    queue.offer(tempNode.right);
                len--;
            }
            res.add(itemList);
        }
        return res;
    }
}

写法2:递归法

时间复杂度: O(n)
空间复杂度: O(n)

/**
 * 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<List<Integer>> resList = new ArrayList<List<Integer>>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        checkFun01(root,0);
        return resList;
    }

    public void checkFun01(TreeNode node, Integer deep) {
        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);
    }
}

相关题目推荐

层序遍历的相关题目比较多,基本都是使用同一个模板,可以练练手:
107. 二叉树的层次遍历 II
199. 二叉树的右视图
637. 二叉树的层平均值
429. N叉树的层序遍历
515. 在每个树行中找最大值
116. 填充每个节点的下一个右侧节点指针
117. 填充每个节点的下一个右侧节点指针 II
104. 二叉树的最大深度
111. 二叉树的最小深度

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

Leetcode 226. 翻转二叉树

题目链接

思路

层序遍历二叉树,每次都将遍历到的节点的左右子树相互交换
在这里插入图片描述

难点

递归写法中的中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次

如果非要使用递归中序的方式写,也可以,如下代码(C++)就可以避免节点左右孩子翻转两次的情况:

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if (root == NULL) return root;
        invertTree(root->left);         // 左
        swap(root->left, root->right);  // 中
        invertTree(root->left);         // 注意 这里依然要遍历左孩子,因为中间节点已经翻转了
        return root;
    }
};

代码(Java)

写法1:递归法

时间复杂度: O(n)
空间复杂度: O(n)

/**
 * 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 TreeNode invertTree(TreeNode root) {
        if(root == null)
            return root;
        //前序遍历
        swapNodes(root);
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }

    private void swapNodes(TreeNode root){
        TreeNode tempNode = root.left;
        root.left = root.right;
        root.right = tempNode;
    }
}

写法2:层序遍历

时间复杂度:O(n)
空间复杂度:O(n)

/**
 * 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 TreeNode invertTree(TreeNode root) {
        if (root == null)
            return null;
        ArrayDeque<TreeNode> deque = new ArrayDeque<>();
        deque.offer(root);

        while (!deque.isEmpty()){
            int len = deque.size();
            while (len>0){
                TreeNode node = deque.poll();
                swapNodes(node);
                if (node.left!=null)
                    deque.offer(node.left);
                if (node.right!=null)
                    deque.offer(node.right);
                len--;
            }
        }
        return root;
        
    }
    private void swapNodes(TreeNode root){
        TreeNode tempNode = root.left;
        root.left = root.right;
        root.right = tempNode;
    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

Leetcode 101. 对称二叉树

题目链接

思路

首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点

对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。

比较的是两个子树的里侧和外侧的元素是否相等。如图所示:
在这里插入图片描述

难点

二叉树类的题目,在使用递归时,我们需要明确用前中后序哪种遍历方式。这题我们只能使用后序遍历(左右中)。因为这题我们要不断收集左右孩子的信息返回给上一个结点。只有后序遍历才能把底部孩子的信息返回给上一层

代码(Java)

写法1:递归法

时间复杂度:O(n)
空间复杂度:O(n)

/**
 * 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 isSymmetric(TreeNode root) {
        return compareNodes(root.left,root.right);
    }

    private boolean compareNodes(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 outside = compareNodes(left.left,right.right);
        boolean inside = compareNodes(left.right,right.left);
        return outside && inside;
    }
}

写法2:迭代法

时间复杂度:O(n)
空间复杂度:O(n)

```java
/**
 * 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 isSymmetric(TreeNode root) {
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offerFirst(root.left);
        deque.offerLast(root.right);
        while (!deque.isEmpty()) {
            TreeNode leftNode = deque.pollFirst();
            TreeNode rightNode = deque.pollLast();
            
        if (leftNode == null && rightNode == null) {
                continue;
            }

        if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
                return false;
            }

            deque.offerFirst(leftNode.left);
            deque.offerFirst(leftNode.right);
            deque.offerLast(rightNode.right);
            deque.offerLast(rightNode.left);
        }
        return true;

    }
}

代码随想录链接

下面是代码随想录的文章链接与视频链接,帮助大家更好地理解这道题。
文章
视频

总结

今天继续学习了二叉树,主要学习了层序遍历法递归法。在运用递归法解决二叉树问题时,需要明确到底是用前中序遍历哪种遍历。层序遍历的写法较为固定,是一种模版。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fuego91

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值