幾道和「二叉樹」有關的演算法面試題

程式設計師吳師兄發表於2019-03-18

1. 二叉樹的前序遍歷

題目來源於 LeetCode 第 144 號問題:二叉樹的前序遍歷。

題目描述

給定一個二叉樹,返回它的 前序 遍歷。

題目解析

用**棧(Stack)**的思路來處理問題。

前序遍歷的順序為根-左-右,具體演算法為:

  • 把根節點push到棧中
  • 迴圈檢測棧是否為空,若不空,則取出棧頂元素,儲存其值
  • 看其右子節點是否存在,若存在則push到棧中
  • 看其左子節點,若存在,則push到棧中。

動畫描述

二叉樹的前序遍歷

程式碼實現

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        List<Integer> list = new LinkedList<>();
        if(root == null){
            return list;
        }
        //第一步是將根節點壓入棧中
        stack.push(root);
        //當棧不為空時,出棧的元素插入list尾部。
        while(!stack.isEmpty()){
            root = stack.pop();
            list.add(root.val);
            if(root.right != null) stack.push(root.right);
            if(root.left != null) stack.push(root.left);
        }
        return list;
    }
}
複製程式碼

2. 二叉樹的中序遍歷

題目來源於 LeetCode 第 94 號問題:二叉樹的中序遍歷。

題目描述

給定一個二叉樹,返回它的 中序 遍歷。

題目解析

用**棧(Stack)**的思路來處理問題。

中序遍歷的順序為左-根-右,具體演算法為:

  • 從根節點開始,先將根節點壓入棧
  • 然後再將其所有左子結點壓入棧,取出棧頂節點,儲存節點值
  • 再將當前指標移到其右子節點上,若存在右子節點,則在下次迴圈時又可將其所有左子結點壓入棧中

動畫描述

二叉樹的中序遍歷

程式碼實現

class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> list = new ArrayList<>();
            Stack<TreeNode> stack = new Stack<>();
            TreeNode cur = root;
            while (cur != null || !stack.isEmpty()) {
                if (cur != null) {
                    stack.push(cur);
                    cur = cur.left;
                } else {
                    cur = stack.pop();
                    list.add(cur.val);
                    cur = cur.right;
                }
            }
            return list;
        }
}
複製程式碼

3. 二叉樹的後序遍歷

題目來源於 LeetCode 第 145 號問題:二叉樹的後序遍歷。

題目描述

給定一個二叉樹,返回它的 後序 遍歷。

題目解析

用**棧(Stack)**的思路來處理問題。

後序遍歷的順序為左-右-根,具體演算法為:

  • 先將根結點壓入棧,然後定義一個輔助結點head
  • while迴圈的條件是棧不為空
  • 在迴圈中,首先將棧頂結點t取出來
  • 如果棧頂結點沒有左右子結點,或者其左子結點是head,或者其右子結點是head的情況下。我們將棧頂結點值加入結果res中,並將棧頂元素移出棧,然後將head指向棧頂元素
  • 否則的話就看如果右子結點不為空,將其加入棧
  • 再看左子結點不為空的話,就加入棧

動畫描述

二叉樹的後序遍歷

程式碼實現

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<Integer>();
    if(root == null)
        return res;
    Stack<TreeNode> stack = new Stack<TreeNode>();
    stack.push(root);
    while(!stack.isEmpty()){
        TreeNode node = stack.pop();
        if(node.left != null) stack.push(node.left);//和傳統先序遍歷不一樣,先將左結點入棧
        if(node.right != null) stack.push(node.right);//後將右結點入棧
        res.add(0,node.val);                        //逆序新增結點值
    }     
    return res;
   }
}
複製程式碼

4. 二叉樹的層序遍歷

題目來源於 LeetCode 第 102 號問題:二叉樹的層序遍歷。

題目描述

給定一個二叉樹,返回其按層次遍歷的節點值。 (即逐層地,從左到右訪問所有節點)。

例如: 給定二叉樹: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
複製程式碼

返回其層次遍歷結果:

[
  [3],
  [9,20],
  [15,7]
]
複製程式碼

題目解析

該問題需要用到佇列

  • 建立一個queue
  • 先把根節點放進去,這時候找根節點的左右兩個子節點
  • 去掉根節點,此時queue裡的元素就是下一層的所有節點
  • 用for迴圈遍歷,將結果存到一個一維向量裡
  • 遍歷完之後再把這個一維向量存到二維向量裡
  • 以此類推,可以完成層序遍歷

動畫描述

二叉樹的層序遍歷

程式碼實現

public List<List<Integer>> levelOrder(TreeNode root) {
    if(root == null)
        return new ArrayList<>();
    List<List<Integer>> res = new ArrayList<>();
    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.add(root);
    while(!queue.isEmpty()){
        int count = queue.size();
        List<Integer> list = new ArrayList<Integer>();
        while(count > 0){
            TreeNode node = queue.poll();
            list.add(node.val);
            if(node.left != null)
                queue.add(node.left);
            if(node.right != null)
                queue.add(node.right);
            count--;
        }
        res.add(list);
    }
    return res;
}
複製程式碼

5. 平衡二叉樹

題目來源於 LeetCode 第 110 號問題:平衡二叉樹。

題目描述

給定一個二叉樹,判斷它是否是高度平衡的二叉樹。

題目解析

採取後序遍歷的方式遍歷二叉樹的每一個結點。

在遍歷到一個結點之前已經遍歷了它的左右子樹,那麼只要在遍歷每個結點的時候記錄它的深度(某一結點的深度等於它到葉結點的路徑的長度),就可以一邊遍歷一邊判斷每個結點是不是平衡的。

程式碼實現

class Solution {
    private boolean isBalanced = true;
    public boolean isBalanced(TreeNode root) {
        getDepth(root);
        return isBalanced;
    }
      public int getDepth(TreeNode root) {
      if (root == null)
			return 0;
		int left = getDepth(root.left);
		int right = getDepth(root.right);
		if (Math.abs(left - right) > 1) {
			isBalanced = false;
		}
		return right > left ? right + 1 : left + 1;
      }
}
複製程式碼

6. 對稱二叉樹

題目來源於 LeetCode 第 101 號問題:對稱二叉樹。

題目描述

給定一個二叉樹,檢查它是否是映象對稱的。

例如,二叉樹 [1,2,2,3,4,4,3] 是對稱的。

    1
   / \
  2   2
 / \ / \
3  4 4  3
複製程式碼

題目解析

用遞迴做比較簡單:一棵樹是對稱的等價於它的左子樹和右子樹兩棵樹是對稱的,問題就轉變為判斷兩棵樹是否對稱。

程式碼實現

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) return true;
        //把問題變成判斷兩棵樹是否是對稱的
        return isSym(root.left, root.right);
    }
    //判斷的是根節點為r1和r2的兩棵樹是否是對稱的
    public boolean isSym(TreeNode r1, TreeNode r2){
        if(r1 == null && r2 == null) return true;
        if(r1 == null || r2 == null) return false;
        //這兩棵樹是對稱需要滿足的條件:
        //1.倆根節點相等。 2.樹1的左子樹和樹2的右子樹,樹2的左子樹和樹1的右子樹都得是對稱的
        return r1.val == r2.val && isSym(r1.left, r2.right) 
                            && isSym(r1.right, r2.left);
    }
}
複製程式碼

7. 重建二叉樹

題目來源於 劍指 offer :重建二叉樹。

題目描述

根據二叉樹的前序遍歷和中序遍歷的結果,重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。

preorder = [3,9,20,15,7]
inorder =  [9,3,15,20,7]
複製程式碼

題目解析

前序遍歷的第一個值為根節點的值,使用這個值將中序遍歷結果分成兩部分,左部分為樹的左子樹中序遍歷結果,右部分為樹的右子樹中序遍歷的結果。

動畫描述

動畫來源於 CS-Notes

程式碼實現

// 快取中序遍歷陣列每個值對應的索引
private Map<Integer, Integer> indexForInOrders = new HashMap<>();

public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
    for (int i = 0; i < in.length; i++)
        indexForInOrders.put(in[i], i);
    return reConstructBinaryTree(pre, 0, pre.length - 1, 0);
}

private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL) {
    if (preL > preR)
        return null;
    TreeNode root = new TreeNode(pre[preL]);
    int inIndex = indexForInOrders.get(root.val);
    int leftTreeSize = inIndex - inL;
    root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL);
    root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1);
    return root;
}
複製程式碼

幾道和「二叉樹」有關的演算法面試題

相關文章