[置顶] 【LeetCode】103. Binary Tree Zigzag Level Order Traversal 解题报告

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51524241

Subject

出处:https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/

Given a binary tree, return the zigzag level order traversal of its nodes’ values. (ie, from left to right, then right to left for the next level and alternate between).

For example:
Given binary tree {3,9,20,#,#,15,7},

    3
   / \   9  20
    /  \    15   7

return its zigzag level order traversal as:

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

Explain

该题目与之前两题非常相似。

【LeetCode】102. Binary Tree Level Order Traversal 解题报告 是从顶层往下从左往右的次序 遍历结点。

【LeetCode】107. Binary Tree Level Order Traversal II 解题报告 是从底层向上从左往右的次序 遍历结点。

而该题目的意思是从顶层向下,”之字形” 顺序输出结点。(第一层从左向右,第二层从右向左,第三层从左向右……依次类推)。

Solution

solution 1

第一种方案使用【102】题目中的非递归方法 进行修改。

主要就是记录当前结点所在的层级,或者当前层的结点的个数

遇到需要反向的层的时候,调用Collections.reverse()方法或者使用LinkedList的addFirst()方法,还可以使用ArrayList的add(0, E)方法 (该方法效率不高,需要拷贝数组)。

    /** * 3ms <br /> * * beats 14.87% of java submissions * * @author jacksen * @param root * @return */
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();

        if (root == null) {
            return result;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        int i = queue.size(); // 记录每层的结点个数
        boolean flag = false;
        TreeNode tempNode = null;
        List<Integer> singleLevel = new ArrayList<>();
        while (!queue.isEmpty()) {
            if (i == 0) {// 一层记录结束
                //
                if (flag) {
                    Collections.reverse(singleLevel);
                }
                result.add(singleLevel);
                //
                flag = !flag;

                i = queue.size();
                singleLevel = new ArrayList<>();
            }
            tempNode = queue.poll();
            singleLevel.add(tempNode.val);

            --i;

            if (tempNode.left != null) {
                queue.add(tempNode.left);
            }
            if (tempNode.right != null) {
                queue.add(tempNode.right);
            }

        }
        if (flag) {
            Collections.reverse(singleLevel);
        }
        result.add(singleLevel);

        return result;
    }
    /** * 2ms <br /> * * beats 60.36% of java submissions * * @author jacksen * @param root * @return */
    public List<List<Integer>> zigzagLevelOrder5(TreeNode root) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if (root == null) {
            return result;
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        int i = queue.size(); // 记录每层的结点个数
        boolean flag = true;
        TreeNode tempNode = null;
        LinkedList<Integer> singleLevel = new LinkedList<>();
        while (!queue.isEmpty()) {
            if (i == 0) {// 一层记录结束
                //
                result.add(singleLevel);
                //
                i = queue.size();
                singleLevel = new LinkedList<>();
                flag = !flag;
            }
            tempNode = queue.poll();
            if (flag) {
                singleLevel.add(tempNode.val);
            } else {
                singleLevel.addFirst(tempNode.val);
            }

            --i;

            if (tempNode.left != null) {
                queue.offer(tempNode.left);
            }
            if (tempNode.right != null) {
                queue.offer(tempNode.right);
            }

        }

        result.add(singleLevel);
        return result;
    }

solution 2

通过递归方式。

将【102】题目中的递归方法 进行改造。

因为有层级这个变量,所以需要在每次递归时,判断 level % 2 是否为0 即可。

    /** * 递归方式 <br /> * 重要的是记录层级, 加上一个标识标识是否集合反向<br /> * * 1ms<br /> * eats96.02% of java submissions * * @author jacksen * @param root * @return */
    public List<List<Integer>> zigzagLevelOrder2(TreeNode root) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();

        // levelRecursion(root, result, 0, false);
        levelRecursion2(root, result, 0);

        return result;
    }
    /** * 递归方法 */
    private void levelRecursion(TreeNode node, List<List<Integer>> result,
            int level, boolean flag) {
        if (node == null) {
            return;
        }
        if (result.size() < level + 1) {// 说明还需要添加一行
            result.add(new LinkedList<Integer>());
        }
        if (flag) {
            ((LinkedList<Integer>) result.get(level)).addFirst(node.val);
        } else {
            result.get(level).add(node.val);
        }

        levelRecursion(node.left, result, level + 1, !flag);
        levelRecursion(node.right, result, level + 1, !flag);
    }

    /** * 可以直接通过level层级判断是否需要addFirst,不必要再添加额外的标识 * * @param node * @param result * @param level */
    private void levelRecursion2(TreeNode node, List<List<Integer>> result,
            int level) {
        if (node == null) {
            return;
        }
        if (result.size() < level + 1) {// 说明还需要添加一行
            result.add(new LinkedList<Integer>());
        }
        if (level % 2 != 0) {
            ((LinkedList<Integer>) result.get(level)).addFirst(node.val);
        } else {
            result.get(level).add(node.val);
        }

        levelRecursion2(node.left, result, level + 1);
        levelRecursion2(node.right, result, level + 1);
    }

该方法效率最高

LeetCode 平台 Run Time 是 1ms

beats 96.02 % of java submissions.

solution 3

该题目的Tags 显示了一个“Stack”标签。
说明可以通过栈的方式来做。

    /** * 用两个栈的方式 <br /> * 3ms <br /> * beats 14.87% of java submissions * * @author jacksen * @param node * @return */
    public List<List<Integer>> zigzagLevelOrder3(TreeNode root) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();

        if (root == null) {
            return result;
        }

        Stack<TreeNode> forwardStack = new Stack<>();
        Stack<TreeNode> retrorseStack = new Stack<>();

        forwardStack.push(root);

        TreeNode tempNode = null;
        List<Integer> singleList = new ArrayList<>();
        while (!forwardStack.isEmpty() || !retrorseStack.isEmpty()) {
            while (!forwardStack.isEmpty()) {
                tempNode = forwardStack.pop();
                singleList.add(tempNode.val);
                if (tempNode.left != null) {
                    retrorseStack.push(tempNode.left);
                }
                if (tempNode.right != null) {
                    retrorseStack.push(tempNode.right);
                }
            }

            if (!singleList.isEmpty()) {
                result.add(singleList);
                singleList = new ArrayList<>();
            }

            while (!retrorseStack.isEmpty()) {
                tempNode = retrorseStack.pop();
                singleList.add(tempNode.val);
                if (tempNode.right != null) {
                    forwardStack.push(tempNode.right);
                }
                if (tempNode.left != null) {
                    forwardStack.push(tempNode.left);
                }
            }

            if (!singleList.isEmpty()) {
                result.add(singleList);
                singleList = new ArrayList<>();
            }
        }

        return result;
    }

两个栈,一个从左向右遍历的层,一个存储从右向左遍历的层。

solution 4

之字形层序输出,主要就是上一层从左向右,下一层从右向左。故而需要一个标志来进行区分。

从该题目的【Discuss】中看到一种使用Deque – 双端队列的解法。

    /** * deque <b>双端队列</b> <br /> * 3ms <br/> * beats 14.87% of java submissions * * @author https://leetcode.com/discuss/89116/java-bfs-with-deque * * @param root * @return */
    public List<List<Integer>> zigzagLevelOrder4(TreeNode root) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        if (root == null) {
            return result;
        }

        boolean flag = true;
        TreeNode tempNode = null;
        TreeNode lastNode = root;

        List<Integer> singleLevel = new ArrayList<>();

        Deque<TreeNode> deque = new LinkedList<>();
        deque.offer(root);

        while (!deque.isEmpty()) {
            tempNode = flag ? deque.pollFirst() : deque.pollLast();
            singleLevel.add(tempNode.val);
            if (flag) {// left->right顺序添加到对尾
                if (tempNode.left != null) {
                    deque.offerLast(tempNode.left);
                }
                if (tempNode.right != null) {
                    deque.offerLast(tempNode.right);
                }
            } else {
                if (tempNode.right != null) {
                    deque.offerFirst(tempNode.right);
                }
                if (tempNode.left != null) {
                    deque.offerFirst(tempNode.left);
                }
            }
            if (tempNode == lastNode) {
                result.add(singleLevel);// 搞定一层
                singleLevel = new ArrayList<>();
                lastNode = flag ? deque.peekFirst() : deque.peekLast();
                flag = !flag;
            }
        }

        return result;
    }

它的思想就是:

flag是true的时候,将节点从左向右添加到队尾。这样从队尾pollLast()的时候,顺序就是从右向左;
flag是false的时候,将节点从右向左添加到对头,这样从对头pollFirst()的时候,顺序就是从左向右。

【102】【107】【103】这些题目大体都是类似的。都是层序遍历输出二叉树。只不过顺序有差别而已。

大家可以举一反三。可以想想怎么从底层向上之字形层序遍历二叉树

bingo~~

你可能感兴趣的:(LeetCode,tree,binary,traversal,ZigZag)