当前位置:   article > 正文

[LeetCode 144] Binary Tree Preorder Traversal

[LeetCode 144] Binary Tree Preorder Traversal
Question:

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

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

        1
         \
          2
         /
        3
  • 1
  • 2
  • 3
  • 4
  • 5

return [1,2,3].

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

Approach #1 Recursive [Accepted]

Detail Explaination
The first method to solve this problem is using recursive.
This is the classical method and straightforward. we can define a helper function to implement recursion.
The java code is as following:

Java

public List<Integer> inorderTraversal(TreeNode root) {
  List<Integer> res = new ArrayList<>();
  helper(root, res);
  return res;
}

public void helper(TreeNode root, List<Integer> res) {
  if (root != null) {
    res.add(root.val);
    if (root.left != null) {
      helper(root.left, res);
    }
    if (root.right != null) {
      helper(root.right, res);
    }
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Complexity Analysis

  • Time complexity : O(n). The time complexity is O(n)because the recursive function is T(n)=2T(n/2)+1.

  • Space complexity : The worst case is O(n), and the average caes is O(log(n)) where n is number of nodes.


Approach #2 Iterating method using Stack [Accepted]

Detail Explaination
The strategy is very similiar to the first method, the different is using stack. For each node
if the node is not null, we add it’s value in the result, then if the node has the right child,
push the right in the stack and if the node has left child, update node as it’s left child.
if the stack is not empty and the node is null, we update the node as stack.pop().

Here is an Example:
       1
     /   \
    2     3
   / \
  4   5

step1 : res[1]; curr = 2; stack[3];
step2 : res[1,2]; curr = 4; stack[3,5];
step3 : res[1,2,4]; curr = null; stack[3,5];
step4 : curr == null && stack is not empty -> curr = 5; stack[3];
step5 : res[1,2,4,5]; curr == null; stack[3];
step6 : curr == null && stack is not empty -> curr = 3; stack[];
step7 : res[1,2,4,5,3]; curr == null; stack is empty;
step8 : return [1,2,4,5,3]

Comment: the preorder traversal is root->root.left->root.right,
if the root.right is not null, we push it in the stack
which make sure the order we process the right subtree,
this is the reason we use stack.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

Java

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;
        while (curr != null) {
            res.add(curr.val);

            if (curr.right != null) {
                stack.push(curr.right);
            }
            curr = curr.left;
            if (curr == null && !stack.isEmpty()) {
                curr = stack.pop();
            }
        }
        return res;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Complexity Analysis

  • Time complexity : O(n).
  • Time complexity: O(n).

Approach #3 Morris Traversal [Accepted]

Detail Explaination
This method we have to use a new data structure Threaded Binary Tree and the strategy is as follows:

Step1. Initialize current as root
Step2. While current is not NULL
 If current does not have left child
 a. Add current’s value
 b. Go to the right, i.e., current = current.right
Else
 a. add current's value.
 b. In current's left subtree, make current's right the right child of the rightmost node
 c. Go to this left child, i.e., current = current.left
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
For Example:
  curr->(1)
       /   \
      2     3
     / \   /
    4   5 6
res[];
First: 1 is the root, so initial 1 as current, 1 has left child which is 2, the current's left subtree is
        2
       / \
      4   5
so in this subtree, the rightmost node is 5, then make the current(1)'s right as the right child of 5. Set current = cuurent.left (current = 2).
The tree now looks like:
          1
         /
curr-> (2)
       / \
      4   5
           \
            3
            /
          6
res[1];
For current, 2, which has left child 4, so make the current's right as it's left subtree's right most node(4)'s right child
           1
          /
         2
        /
curr->(4)
        \
          5
           \
            3
            /
           6
res[1,2];
then add 4 because it has no left child, then add 5,3 one by one, for node 3 which has left child 6, do the same as above.
Finally, the inoder taversal is [1,2,4,5,3,6].
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

For more detail, please check
Threaded binary tree

Java

class Solution {
public List<Integer> preorderTraversal(TreeNode node) {
        List<Integer> list = new ArrayList();

        while(node != null) {
            if(node.left == null) {
                list.add(node.val);
                node = node.right;
            }
            else {
                TreeNode nextNode = node.left;

                TreeNode p = nextNode;
                while(p.right != null) p = p.right;

                list.add(node.val);
                p.right = node.right;
                node = nextNode;
            }
        }
        return list;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Complexity Analysis

  • Time complexity : O(n). To prove that the time complexity is O(n),
    the biggest problem lies in finding the time complexity of finding the predecessor nodes of all the nodes in the binary tree.
    Intuitively, that complexity is O(nlogn), because to find the predecessor node for a single node related to the height of the tree.
    But in fact, finding the predecessor nodes for all nodes only needs O(n) time. Because n nodes in a Binary-Tree has n-1 edges, the whole processing for each edges up to 2 times, one is to locate a node, and the other is to find the predecessor node.
    So the complexity is O(n).
  • Space complexity : O(1). The space complexity of Morris Traversal is O(1) because it just needs 2 “assisting” pointers.

[My LeetCode Explanation]
https://discuss.leetcode.com/topic/100806/solution-by-monkeykingyan

Samiliar Questions

LeetCode 94: Binary Tree Inorder Traversall

Video Explanation

[LeetCode 144: Binary Tree Preorder Traversal]
https://www.youtube.com/watch?v=4czxqPr_UVc&t=164s

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/算法构造者/article/detail/62914
推荐阅读
相关标签
  

闽ICP备14008679号