LeetCode145. Binary Tree Postorder Traversal 解题报告

Posted 月盡天明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode145. Binary Tree Postorder Traversal 解题报告相关的知识,希望对你有一定的参考价值。


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


Subject

出处:https://leetcode.com/problems/binary-tree-postorder-traversal/

Hard 级别

Given a binary tree, return the postorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},
   1
    \\
     2
    /
   3
return [3,2,1].

Explain

求二叉树的后续遍历。


Solution

solution 1

递归方式

    private List<Integer> resultList = new ArrayList<Integer>();

    /**
     * 递归方式 <br />
     * 1ms
     * 
     * @param root
     * @return
     */
    public List<Integer> postorderTraversal(TreeNode root) {
        postOrder(root);
        return resultList;
    }

    private void postOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        if (node.left != null) {
            postOrder(node.left);
        }
        if (node.right != null) {
            postOrder(node.right);
        }
        resultList.add(node.val);
    }

LeetCode上Run Time 是 1ms

Your runtime beats 70.01% of java submissions.


solution 2

非递归方式的思想就是需要记录访问的结点是否是第一次访问的。因为当前结点需要在左右子数访问之后才能输出

所以需要标志来记录当前结点是否是第一次访问。当第二次访问的时候才输出。

    /**
     * 后续遍历非递归方法
     * 根据中序非递归方式改造而来
     * @author jacksen
     * @param node
     */
    public List<Integer> postorderTraversal1(TreeNode node) {
        if (node == null) {
            return resultList;
        }
        Stack<WrapperNode> stack = new Stack<>();
        WrapperNode wrapperNode = new WrapperNode(node, false);
        stack.push(wrapperNode);
        while (!stack.isEmpty()) {
            while ((wrapperNode = stack.peek()).node != null) {
                wrapperNode = new WrapperNode(wrapperNode.node.left, false);
                stack.push(wrapperNode);
            }
            //
            stack.pop();
            //
            wrapperNode = stack.peek();
            while (wrapperNode.node != null) {
                if (wrapperNode.isFinished) {
                    resultList.add(stack.pop().node.val);
                    if (stack.isEmpty()) {
                        return resultList;
                    }
                    wrapperNode = stack.peek();
                } else {
                    wrapperNode.isFinished = true;
                    wrapperNode = new WrapperNode(wrapperNode.node.right, false);
                    stack.push(wrapperNode);
                    break;
                }
            }
        }
        return resultList;
    }
    /**
     * TreeNode包装类
     * 
     * @author jacksen
     */
    private static class WrapperNode {
        TreeNode node;
        boolean isFinished;

        public WrapperNode(TreeNode node, boolean isFinished) {
            this.node = node;
            this.isFinished = isFinished;
        }
    }

先从根节点往左,把最左侧的一条分支入栈。
最左侧走到叶子结点之后,去添加它的右子数。并将当前结点访问标志改变。

判断访问标志来pop结点


solution 3

solution 2的非递归方式,是先访问左子树。
其实可以从根结点,然后访问右子树。

参照 : http://www.cnblogs.com/Antech/p/3655594.html

    /**
     * 非递归方式 <br />
     * 3ms <br />
     * http://www.cnblogs.com/Antech/p/3655594.html
     * 
     * @param root
     * @return
     */
    private List<Integer> postorderTraversal2(TreeNode root) {
        if (root == null) {
            return resultList;
        }
        Stack<WrapperNode> stack = new Stack<>();
        stack.push(new WrapperNode(root, false));
        WrapperNode wrapperNode = null;
        while (!stack.isEmpty()) {
            wrapperNode = stack.peek();
            if (wrapperNode.node == null) {
                stack.pop();
                continue;
            }
            if (wrapperNode.isFinished) {
                resultList.add(stack.pop().node.val);
            } else {
                stack.push(new WrapperNode(wrapperNode.node.right, false));
                stack.push(new WrapperNode(wrapperNode.node.left, false));
                wrapperNode.isFinished = true;
            }
        }
        return resultList;
    }

solution 4

在solution 3的基础上进行改进。

判断左右子节点是否为null,进而少一次while判断,也少入栈出栈操作。

    /**
     * 方法二非递归方式的改进 <br />
     * 3ms <br />
     * 
     * @param root
     * @return
     */
    private List<Integer> postorderTraversal3(TreeNode root) {
        if (root == null) {
            return resultList;
        }
        Stack<WrapperNode> stack = new Stack<>();
        stack.push(new WrapperNode(root, false));
        WrapperNode wrapperNode = null;
        while (!stack.isEmpty()) {
            wrapperNode = stack.peek();
            if (wrapperNode.isFinished) {
                resultList.add(stack.pop().node.val);
            } else {
                wrapperNode.isFinished = true;
                if (wrapperNode.node.right != null) {
                    stack.push(new WrapperNode(wrapperNode.node.right, false));
                }
                if (wrapperNode.node.left != null) {
                    stack.push(new WrapperNode(wrapperNode.node.left, false));
                }
            }
        }
        return resultList;
    }

solution 5

接下来介绍一个牛逼的方法。
该方法使用两个栈进行处理,代码看上去简单易懂。

    /**
     * 使用两个栈 <br />
     * 2ms <br />
     * 
     * https://leetcode.com/discuss/102843/my-ac-java-solution-using-two-stacks
     * 
     * @param root
     * @return
     */
    private List<Integer> postorderTraversal4(TreeNode root) {
        if (root == null) {
            return resultList;
        }
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();

        stack1.push(root);

        TreeNode tempNode = null;

        while (!stack1.isEmpty()) {
            tempNode = stack1.pop();
            if (tempNode.left != null) {
                stack1.push(tempNode.left);
            }
            if (tempNode.right != null) {
                stack1.push(tempNode.right);
            }
            stack2.push(tempNode);
        }

        while (!stack2.isEmpty()) {
            resultList.add(stack2.pop().val);
        }

        return resultList;
    }

对该方法仔细研究,就会发现stack2里面存储的就是后续遍历输出的整个顺序。

后序遍历就是【左右根】的形式输出。

所以stack1中先入根然后pop出来,然后入左和右。这样stack1先pop根,然后pop右,接着pop左
正好,stack2先入根,然后入右,接着入左。

故,stack2 循环pop的时候就是【左右根】的顺序。


solution 6

其实,仔细想想,先序输出的时候是【根左右】,后序输出是【左右根】,
所以只需要按照先序遍历非递归的方法,输出的时候改改顺序即可。

    /**
     * https://leetcode.com/discuss/71943/preorder-inorder-and-postorder-
     * iteratively-summarization <br />
     * 
     * LinkedList
     * 
     * @param root
     * @return
     */
    public List<Integer> postorderTraversal5(TreeNode root) {
        LinkedList<Integer> list = new LinkedList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode tempNode = root;
        while (!stack.isEmpty() || tempNode != null) {
            if (tempNode != null) {
                stack.push(tempNode);
                list.addFirst(tempNode.val);
                tempNode = tempNode.right;
            } else {
                tempNode = stack.pop().left;
            }
        }

        return list;
    }

该方法使用LinkedList

每次都调用addFirst()方法,将结点添加到头部

所以顺序就是【左】【右】【根】


solution 7

根据solution 6的思想和solution 7的方式,可以将先序遍历非递归方式简单修改一下即可。

Binary Tree Inorder Traversal 非递归方法

    /**
     * 非递归方式 <br />
     * 
     * 参考 Pre order 的preorderTraversal2
     * 
     * @author jacksen
     * 
     * @param root
     * @return
     */
    public List<Integer> postorderTraversal6(TreeNode root) {
        LinkedList<Integer> list = new LinkedList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        TreeNode tempNode = null;
        while (!stack.isEmpty()) {
            tempNode = stack.pop();
            list.addFirst(tempNode.val);
            if (tempNode.left != null) {
                stack.push(tempNode.left);
            }
            if (tempNode.right != null) {
                stack.push(tempNode.right);
            }
        }
        return list;
    }

该方法使用一个栈加上一个单链表。


OK! 介绍完毕~

欢迎留言,批评指正~~~

以上是关于LeetCode145. Binary Tree Postorder Traversal 解题报告的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 145. Binary Tree Postorder Traversal

LeetCode 145:Binary Tree Postorder Traversal

leetcode145. Binary Tree Postorder Traversal

LeetCode 145: Binary Tree Postorder Traversal

leetcode No145. Binary Tree Postorder Traversal

LeetCode OJ 145. Binary Tree Postorder Traversal