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]
複製程式碼
題目解析
前序遍歷的第一個值為根節點的值,使用這個值將中序遍歷結果分成兩部分,左部分為樹的左子樹中序遍歷結果,右部分為樹的右子樹中序遍歷的結果。
動畫描述
程式碼實現
// 快取中序遍歷陣列每個值對應的索引
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;
}
複製程式碼