Loading

Medium | LeetCode 103 | 剑指 Offer 32 - III. 从上到下打印二叉树 III | 二叉树层次遍历

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

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

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

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

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

方法一: 双栈

由于在遍历时, 当前层的遍历顺序与下一层的遍历顺序相反, 即本层的先放到栈的孩子在遍历下一层时后遍历, 后放到栈的孩子在遍历下一层时先遍历。所以应当使用栈的数据结构。

使用两个栈实现, 一个栈用于遍历本层的节点, 另一个栈用于存放下一层的节点。

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    Deque<TreeNode> stack1 = new ArrayDeque<>();
    Deque<TreeNode> stack2 = new ArrayDeque<>();
    stack1.addLast(root);
    while (!stack1.isEmpty()) {
        List<Integer> res1 = new ArrayList<>();
        while(!stack1.isEmpty()) {
            TreeNode node = stack1.pop();
            res1.add(node.val);
            // 本层是奇数层, 遍历的顺序是从左到右, 所以添加孩子的顺序是先添加左孩子, 再添加右孩子
            if (node.left != null) {
                stack2.push(node.left);
            }
            if (node.right != null) {
                stack2.push(node.right);
            }
        }
        res.add(res1);

        // 接着遍历偶数层
        List<Integer> res2 = new ArrayList<>();
        while(!stack2.isEmpty()) {
            TreeNode node = stack2.pop();
            res2.add(node.val);
            // 偶数层遍历的顺序是从右到左, 所以应当先添加右孩子, 再添加左孩子
            if (node.right != null) {
                stack1.push(node.right);
            }
            if (node.left != null) {
                stack1.push(node.left);
            }
        }
        if (res2.size() > 0) {
            res.add(res2);
        }
    }
    return res;
}

方法二: 双端队列

public List<List<Integer>> levelOrder(TreeNode root) {
    Queue<TreeNode> queue = new LinkedList<>();
    List<List<Integer>> res = new ArrayList<>();
    if(root != null) queue.add(root);
    while(!queue.isEmpty()) {
        LinkedList<Integer> tmp = new LinkedList<>();
        // 入队到queue的过程还是和普通的层次队列一样
        for(int i = queue.size(); i > 0; i--) {
            TreeNode node = queue.poll();
            // 不过出队添加到结果集的过程, 添加到结果集的头部还是尾部就不同了
            if(res.size() % 2 == 0) tmp.addLast(node.val); // 偶数层 -> 队列头部
            else tmp.addFirst(node.val); // 奇数层 -> 队列尾部
            if(node.left != null) queue.add(node.left);
            if(node.right != null) queue.add(node.right);
        }
        res.add(tmp);
    }
    return res;
}

方法三:奇偶层逻辑分离

和方法一类似, 不过这里并不需要使用两个队列或者栈, 这里使用一个队列, 不过遍历的顺序是不同的, 和方法一类似, 奇数层的时候, 从从头部出队, 偶数层的时候是从尾部出队, 所以其添加孩子的顺序也不相同。

public List<List<Integer>> levelOrder(TreeNode root) {
    Deque<TreeNode> deque = new LinkedList<>();
    List<List<Integer>> res = new ArrayList<>();
    if(root != null) deque.add(root);
    while(!deque.isEmpty()) {
        // 打印奇数层
        List<Integer> tmp = new ArrayList<>();
        for(int i = deque.size(); i > 0; i--) {
            // 从左向右打印
            TreeNode node = deque.removeFirst();
            tmp.add(node.val);
            // 先左后右加入下层节点
            if(node.left != null) deque.addLast(node.left);
            if(node.right != null) deque.addLast(node.right);
        }
        res.add(tmp);
        if(deque.isEmpty()) break; // 若为空则提前跳出
        // 打印偶数层
        tmp = new ArrayList<>();
        for(int i = deque.size(); i > 0; i--) {
            // 从右向左打印
            TreeNode node = deque.removeLast();
            tmp.add(node.val);
            // 先右后左加入下层节点
            if(node.right != null) deque.addFirst(node.right);
            if(node.left != null) deque.addFirst(node.left);
        }
        res.add(tmp);
    }
    return res;
}

方法四: 层次遍历 + 倒序

这个方法和方法二类似。层次遍历还是常规的层次遍历的方法, 不过在添加到结果集的时候, 可以根据其层数, 选择是否需要将结果颠倒。

public List<List<Integer>> levelOrder(TreeNode root) {
    Queue<TreeNode> queue = new LinkedList<>();
    List<List<Integer>> res = new ArrayList<>();
    if(root != null) queue.add(root);
    while(!queue.isEmpty()) {
        List<Integer> tmp = new ArrayList<>();
        for(int i = queue.size(); i > 0; i--) {
            TreeNode node = queue.poll();
            tmp.add(node.val);
            if(node.left != null) queue.add(node.left);
            if(node.right != null) queue.add(node.right);
        }
        if(res.size() % 2 == 1) Collections.reverse(tmp);
        res.add(tmp);
    }
    return res;
}
posted @ 2021-01-16 21:59  反身而诚、  阅读(94)  评论(0编辑  收藏  举报