剑指 Offer 从上到下打印二叉树 ⅠⅡⅢ 详细讲解

题目Ⅰ

​​​​​​​​​​​​​​剑指 Offer 32 - I. 从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回:

[3,9,20,15,7]

​​​​​​​​​​​​​​思路

这道题就是最基础的层序遍历,层序遍历就是,广度优先遍历,一层一层的打印。

如何做到层序遍历呢?

我们肯定需要一个指针来按照层序遍历的顺序去移动。

所以我们想到要用队列,按照:每个节点入队列、左孩子入队列、右孩子入队列 这样的顺序,然后每一轮出队列就行。 

具体动态图请参考:​​​​​​​剑指 Offer 32 - I. 从上到下打印二叉树

代码思路

1.将树的根节点加入到对列

2.开始循环:指针指向队列的头,出队列、左孩子入队列、右孩子入队列

我认为最关键的一点就是 通过每次入队列出队列,来让指针指向队列头元素,这样指针就能按照层序遍历的顺序来指向

 代码

class Solution {
    public int[] levelOrder(TreeNode root) {
        if(root == null) return new int[0];
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        ArrayList<Integer> arrayList = new ArrayList<>();
        while (!queue.isEmpty()){
            TreeNode node = queue.poll();
            arrayList.add( node.val );
            if (node.left!=null)queue.add(node.left);
            if (node.right!=null)queue.add(node.right);
        }
        int[] res = new int[arrayList.size()];
        for(int i = 0; i < arrayList.size(); i++)
            res[i] = arrayList.get(i);
        return res;
    }
}

题目Ⅱ

剑指 Offer 32 - II. 从上到下打印二叉树 II - 力扣(LeetCode)

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

思路 

上道题的返回结果是

[3,9,20,15,7]

这道题的返回结果是集合嵌套集合

[ [3], [9,20], [15,7] ]

上道题是将层序遍历的结果放到数组中,这道题其实比上到题难。

上道题,你只需要把每个节点按照层序遍历走一遍就行了,不需要知道哪里具体是分层了,但是这道题要多一个操作,那就是多一个分层的操作。

怎么判断什么时候分层?

起初我想的是,按照树的每层的大小来分层,例如第一层的大小是1,第二层的大小是2,第三层是4,第四层是8,那以此类推,每次记录一个大小,遍历到这个大小的时候就分层。

但是问题是,这不是满二叉树,除了第一层,其他层的大小都是不一定的。

看了题解的代码,恍然大悟。

和上道题一样,先用队列去遍历每个节点,然后何时直到一层遍历完了?

那就是当上一层的元素都出队列之后,下一层的元素都进入队列了,那么这个时候,下一层的大小就是当前队列的大小。

第一层的大小我们知道,它一定是1,那么之后的每层的大小我们都不知道,但是我们可以去算一下,当第一层元素都出队列的时候,第二层都进入队列了,所以当前队列的大小就是第二层的元素的大小。

也就是在第一题层序遍历的基础上加一个for循环判断

            for (int size = queue.size(); size > 0 ; size--) {
                TreeNode node = queue.poll();
                rowList.add(node.val);
                if (node.left!=null)queue.add(node.left);
                if (node.right!=null)queue.add(node.right);
            }

例如下面这个例子

    3
   / \
  9  20
    /  \
   15   7

初始化的时候,3先进入队列。

开始循环:

第一层大小是1,循环1次:3出队列,3的左右孩子进入队列,队列的大小是2

第二层大小是2,循环2次:9出队列 ,9没有左右孩子

20出队列,20的左右孩子入队列,这时候循环2次完毕,队列大小是2,所以下一层的大小是2

第三层大小是2,循环2次:15出队列,15没有左右孩子

7出队类,7没有左右孩子,这时候循环两次结束,队列大小是0,结束循环。

 代码

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        if (root == null)return new LinkedList<>();
        List<List<Integer>> res = new LinkedList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            List<Integer> rowList = new LinkedList<>();
            for (int size = queue.size(); size > 0 ; size--) {
                TreeNode node = queue.poll();
                rowList.add(node.val);
                if (node.left!=null)queue.add(node.left);
                if (node.right!=null)queue.add(node.right);
            }
            res.add(rowList);

        }
        return  res ;

    }
}

题目Ⅲ

剑指 Offer 32 - III. 从上到下打印二叉树 III - 力扣(LeetCode)

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [20,9],
  [15,7]
]

思路 

这道题就是在第二题的基础上加了一个,奇数层的时候打印顺序不变,偶数层的时候,打印顺序相反。

所以,第二题搞懂了的话,第三题直接就多一个判断奇偶,然后翻转一下list就行了

代码

class Solution {
 public  List<List<Integer>> levelOrder(TreeNode root) {
        if (root == null)return new LinkedList<>();
        Queue<TreeNode> queue = new LinkedList();
        List<List<Integer>> res = new LinkedList<>();
        queue.add(root);
        int turn = 0;
        while (!queue.isEmpty()){
            turn++;
            List<Integer> list = new LinkedList<>();

            for (int size = queue.size();size>0 ; size--) {
                TreeNode current = queue.poll();
                list.add(current.val);
                if (current.left != null)queue.add(current.left);
                if (current.right != null)queue.add(current.right);
            }
            if (turn % 2 == 0){        //偶数:从右到左
               //翻转list
                List<Integer> list2 = new LinkedList();
                for (int i  = list.size()-1;i >= 0 ; i--) {
                    list2.add(list.get(i));
                }
                res.add(list2);
            }else {        //奇数:从左到右
                res.add(list);
            }
        }
        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/KangYouWei6/article/details/132313488