[Leetcode] Binary Tree Traversal 二叉樹遍歷

Binary Tree Preorder Traversal

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

For example: Given binary tree {1,#,2,3},數據結構

1
    \
     2
    /
   3

return [1,2,3].post

棧迭代

複雜度

時間 O(b^(h+1)-1) 空間 O(h) 遞歸棧空間 對於二叉樹b=2this

思路

用迭代法作深度優先搜索的技巧就是使用一個顯式聲明的Stack存儲遍歷到節點,替代遞歸中的進程棧,實際上空間複雜度仍是同樣的。對於先序遍歷,咱們pop出棧頂節點,記錄它的值,而後將它的左右子節點push入棧,以此類推。code

代碼

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

Binary Tree Inorder Traversal

Given a binary tree, return the inorder traversal of its nodes' values.遞歸

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

1
    \
     2
    /
   3

return [1,3,2].進程

棧迭代

複雜度

時間 O(b^(h+1)-1) 空間 O(h) 遞歸棧空間 對於二叉樹b=2it

思路

用棧中序遍歷沒有先序遍歷那麼直觀,由於咱們不能立刻pop出當前元素,而要先把它的左子樹都遍歷完才能pop它本身。全部咱們先將將最左邊的全部節點都push進棧,而後再依次pop並記錄值,每pop一個元素後再看它有沒有右子樹,若是右的話,咱們再將它的右節點和右子樹中最左邊的節點都push進棧,再依次pop。io

代碼

public class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new LinkedList<Integer>();
        Stack<TreeNode> s = new Stack<TreeNode>();
        //先將最左邊的節點都push進棧
        if(root!=null){
            pushAllTheLeft(s, root);
        }
        while(!s.isEmpty()){
            TreeNode curr = s.pop();
            res.add(curr.val);
            //若是有右子樹,將右節點和右子樹的最左邊的節點都push進棧
            if(curr.right != null){
                pushAllTheLeft(s, curr.right);
            }
        }
        return res;
    }
    
    private void pushAllTheLeft(Stack<TreeNode> s, TreeNode root){
        s.push(root);
        while(root.left!=null){
            root = root.left;
            s.push(root);
        }
    }
}

Binary Tree Postorder Traversal

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].

棧迭代

複雜度

時間 O(b^(h+1)-1) 空間 O(h) 遞歸棧空間 對於二叉樹b=2

思路

後序遍歷就不能簡單的改變pop順序來實現了,咱們知道根節點(這裏的根節點不是整個樹的根,而是相對於左右節點的跟)是在左右節點都計算完才計算的,因此咱們會遇到兩次根節點,第一次遇到根節點時咱們將左右節點加入棧,但不把根節點pop出去,等處處理完左右節點後,咱們又會遇到一次根節點,這時再計算根節點並把它pop出去。爲了判斷是第一次仍是第二次遇到這個根節點,咱們能夠用一個數據結構把這個信息封裝進去,第一次遇到的時候將其設爲已經訪問了一次,這樣第二次遇到時發現已經訪問了一次,就能夠直接pop了。

代碼

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        Stack<PowerNode> s = new Stack<PowerNode>();
        List<Integer> res = new LinkedList<Integer>();
        if(root!=null) s.push(new PowerNode(root, false));
        while(!s.isEmpty()){
            PowerNode curr = s.peek();
            //若是是第二次訪問,就計算並pop該節點
            if(curr.visited){
                res.add(curr.node.val);
                s.pop();
            } else {
            //若是是第一次訪問,就將它的左右節點加入stack,並設置其已經訪問了一次
                if(curr.node.right!=null) s.push(new PowerNode(curr.node.right, false));
                if(curr.node.left!=null) s.push(new PowerNode(curr.node.left, false));
                curr.visited = true;
            }
        }
        return res;
    }
    
    private class PowerNode {
        TreeNode node;
        boolean visited;
        public PowerNode(TreeNode n, boolean v){
            this.node = n;
            this.visited = v;
        }
    }
}

反向法

複雜度

時間 O(b^(h+1)-1) 空間 O(h) 遞歸棧空間 對於二叉樹b=2

思路

還有一種更巧妙的方法,由於後序遍歷的順序是left - right - root,雖然咱們不方便直接獲得這個順序,可是它的逆序仍是很好獲得的,咱們能夠用root - right - left的順序遍歷樹,而後反向添加結果就好了。

代碼

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        Stack<TreeNode> stk = new Stack<TreeNode>();
        if(root != null) stk.push(root);
        LinkedList<Integer> res = new LinkedList<Integer>();
        while(!stk.isEmpty()){
            TreeNode curr = stk.pop();
            // 先添加左後添加右,就是先訪問右後訪問左
            if(curr.left != null) stk.push(curr.left);
            if(curr.right != null) stk.push(curr.right);
            // 反向添加結果,每次加到最前面
            res.offerFirst(curr.val);
        }
        return res;
    }
}

Binary Tree Level Order Traversal I && II

Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).

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

3
   / \
  9  20
    /  \
   15   7

return its bottom-up level order traversal as: (II)

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

return its level order traversal as: (I)

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

隊列迭代

複雜度

時間 O(b^(h+1)-1) 空間 O(b^h)

思路

本題實質是廣度優先搜索BFS,而用隊列能夠輕鬆的以迭代形式實現它。不過不一樣於BFS的是,層序遍歷須要在隊列中記住每一層的分割點,而BFS不關心層數只要遍歷到指定元素就好了。爲了記住這個分割點,咱們在進入下一層以前先記下這一層的元素個數N(其實就是當前queue的大小),而後只遍歷N個節點(展開下一層節點的同時queue中會新加入不少下下一層的節點)。遍歷完N個節點後記錄新的層數,再進入下一層。對於II,返回的層是逆序的,咱們只要在結果中,每次把下面新一層加到當前這層的前面就好了

代碼

public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new LinkedList<List<Integer>>();
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        if(root != null) q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            List<Integer> level = new LinkedList<Integer>();
            //控制當前層的遍歷次數
            for(int i =0; i < size; i++){
                TreeNode curr = q.poll();
                level.add(curr.val);
                if(curr.left!=null) q.offer(curr.left);
                if(curr.right!=null) q.offer(curr.right);
            }
            res.add(level);
            //對於II, 咱們要逆序加入
            //res.add(0, level)
        }
        return res;
    }
}

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]
]

隊列迭代

複雜度

時間 O(b^(h+1)-1) 空間 O(b^h)

思路

ZigZag遍歷時,奇數層正序記錄,偶數層逆序記錄。能夠經過結果中已有的層數來判斷。

代碼

public class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        List<List<Integer>> res = new LinkedList<List<Integer>>();
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        if(root != null) q.offer(root);
        while(!q.isEmpty()){
            int size = q.size();
            List<Integer> level = new LinkedList<Integer>();
            for(int i =0; i < size; i++){
                TreeNode curr = q.poll();
                //根據結果中已有的層數控制正序仍是逆序
                if(res.size() % 2 == 0){
                    level.add(curr.val);
                } else {
                    level.add(0,curr.val);
                }
                if(curr.left!=null) q.offer(curr.left);
                if(curr.right!=null) q.offer(curr.right);
            }
            res.add(level);
        }
        return res;
    }
}
相關文章
相關標籤/搜索