BinaryTreePreorderTraversal [source code]


public class BinaryTreePreorderTraversal {
static
/******************************************************************************/
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null)
            return res;
        Stack<TreeNode> s = new Stack<>();
        s.push(root);
        while (!s.isEmpty()) {
            TreeNode cur = s.pop();
            res.add(cur.val);
            if (cur.right != null)
                s.push(cur.right);
            if (cur.left != null)
                s.push(cur.left);
        }
        return res;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        BinaryTreePreorderTraversal.Solution tester = new BinaryTreePreorderTraversal.Solution();
    }
}

很熟悉了, 直接做出来; 速度是1ms (23%)

然后尝试用Morris写的一个, 放在这里:

public class Solution {  
    public List<Integer> preorderTraversal(TreeNode root) {  
        List<Integer> res = new ArrayList<>();  
        if (root == null)  
            return res;  
        TreeNode cur = root;  
        while (cur != null) {  
            if (cur.left == null) {  
                res.add(cur.val);  
                cur = cur.right;  
            } else {  
                TreeNode prev = cur.left;  
                while (prev.right != null && prev.right != cur)  
                    prev = prev.right;  
                if (prev.right == null) {  
                    res.add(cur.val);  
                    prev.right = cur;  
                    cur = cur.left;  
                } else {  
                    prev.right = null;  
                    cur = cur.right;  
                }  
            }  
        }  
        return res;  
    }  
}

速度是一样的;


这个是discussion最优解:

public List<Integer> preorderTraversal(TreeNode node) {  
    List<Integer> list = new LinkedList<Integer>();  
    Stack<TreeNode> rights = new Stack<TreeNode>();  
    while(node != null) {  
        list.add(node.val);  
        if (node.right != null) {  
            rights.push(node.right);  
        }  
        node = node.left;  
        if (node == null && !rights.isEmpty()) {  
            node = rights.pop();  
        }  
    }  
    return list;  
}

跟我自己写的ver1也就是traversal-oriented的做法是类似的, 但是不完全类似; 我从讲义上面看到的那个ver1, 其实本质上还是一个stack-oriented; 这里他这个才更像是一个标准的traversal-oriented的思路;

这个是对上面算法的直观改写:

public List<Integer> preorderTraversal(TreeNode root) {  
    List<Integer> result = new LinkedList<>();  
    Deque<TreeNode> stack = new LinkedList<>();  
    TreeNode node = root;  
    while (node != null || !stack.isEmpty()) {  
        if (node != null) {  
            result.add(node.val);  
            stack.push(node.right);  
            node = node.left;  
        } else {  
            node = stack.pop();  
        }  
    }  
    return result;  
}

另外底下回复展开了对复杂度的讨论, 时间是N这个是没有问题的, 但是Stack的做法, 空间其实未必就是N的, WorstCase才是, BestCase好像也可以是O(1)? 比如一个全体往左的line的; 类似的, 如果是一个往右的line, 那么就是WorstCase, 也就是O(N)了;

注意这种复杂度的讨论的前提是N指的是number of nodes而不是height; 不过既然是复杂度, 那么就是要measure input size, 用nodes number好像更合理一些;


这个是对我的ver2的直观改写:

public List<Integer> preorderTraversal(TreeNode root) {  
    List<Integer> result = new LinkedList<>();  
    Deque<TreeNode> stack = new LinkedList<>();  
    stack.push(root);  
    while (!stack.isEmpty()) {  
        TreeNode node = stack.pop();  
        if (node != null) {  
            result.add(node.val);  
            stack.push(node.right);  
            stack.push(node.left);  
        }  
    }  
    return result;  
}

其实唯一的差别也就是when to process null: at leaf or just above leaf;


除开这些好像也没有什么其他的特别好的做法了;


在bittiger的视频上面看到一个无敌的解法:

class Solution {  
    public List<Integer> preorderTraversal(TreeNode root) {  
        List<Integer> res = new ArrayList<> ();  
        Deque<Operation> stack = new ArrayDeque<> ();  
        stack.push (new Operation (0, root));  
        while (!stack.isEmpty ()) {  
            Operation cur = stack.pop ();  
            if (cur.node == null)  
                continue;       // defensive coding, or leaf handling  
            if (cur.action == 1) {  
                res.add (cur.node.val);  
            } else {  
                stack.push (new Operation (0, cur.node.right));  
                stack.push (new Operation (0, cur.node.left));  
                stack.push (new Operation (1, cur.node));  
            }  
        }  
        return res;  
    }  

    static class Operation {  
        // 0 for visit (not print, just pass-by); 1 for print (actually visit this node).   
        // Another way of thinking: or 1 for actually visit this node, 0 for NOT visit.  
        int action;  
        TreeNode node;  
        Operation (int a, TreeNode n) {  
            action = a;  
            node = n;  
        }  
    }  
}

这个解法的无敌之处在于, 你的Stack循环里面每一个iteration反正处理的是一个node, 但是实际上当你手上有这个node的时候, 实际上你的可行性的做法是, 可能你并不visit他(就是这里的0), 也可能你认为应该visit了(对应是1); 所以这样一个flag其实就是控制你在node的时候, 是真的去处理他, 还是去跳过, 类似一个defer的操作;

这个解法的无敌之处在于, 把那三个push的操作稍微调换一下, InOrder和PostOrder直接一样的解法, 真的是大开眼界;


Problem Description

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

For example:
Given binary tree {1,#,2,3},

   1  
    \  
     2  
    /  
   3

return [1,2,3].

Note: Recursive solution is trivial, could you do it iteratively?

Difficulty:Medium
Total Accepted:186.7K
Total Submissions:415.3K
Contributor: LeetCode
Related Topics
tree stack
Similar Questions
Binary Tree Inorder Traversal Verify Preorder Sequence in Binary Search Tree

results matching ""

    No results matching ""