題目
劍指 Offer 27. 二叉樹的映象
思路1(遞迴)
- 我們可以使用深度優先搜尋,先遞迴到連結串列的末尾,然後從末尾開始兩兩交換。就相當於後續遍歷而已
- 記得要先儲存下來
node.right
節點,因為我們在遞迴完左邊才遞迴右邊,而遞迴完左邊的時候,直接把node.right
的指向修改了,如果事先不儲存node.right
節點的話,在遞迴右邊傳入的節點是錯誤的節點,因此得不到正確的答案
程式碼
class Solution {
public TreeNode mirrorTree(TreeNode root) {
return dfs(root);
}
public TreeNode dfs(TreeNode node) {
// 為空說明到底了
if (node == null) {
return null;
}
// 先記錄right節點
TreeNode right = node.right;
// 分別遞迴左邊和右邊,將 left 和 right 的指標互相交換
node.right = mirrorTree(node.left);
node.left = mirrorTree(right);
return node;
}
}
複雜度分析
- 時間複雜度:\(O(N)\),遍歷一遍樹的每個節點要花費\(O(N)\)的時間複雜度
- 空間複雜度:\(O(N)\),最壞情況下是一條連結串列,因此遞迴需要\(O(N)\)的棧空間
思路2(迭代)
- 使用佇列(也可以使用棧,差不多一樣)進行儲存節點,就是數的層序遍歷
- 節點是按順序入隊,因此我們需要做的就是將隊頭元素出隊,然後將他的兩個子節點入隊,再交換兩個子節點的值就可以完成一個子節點左右孩子的交換,重複所有的節點
- 其實就是從樹根到樹葉將每個子節點都進行交換,最終完成了整個樹的交換,形成映象
程式碼
class Solution {
public TreeNode mirrorTree(TreeNode root) {
if (root == null) {
return null;
}
// 使用佇列儲存節點
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
// 將子節點入隊
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
// 交換左右兩個子節點
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
return root;
}
}
複雜度分析
- 時間複雜度:\(O(N)\)
- 空間複雜度:\(O(N)\),棧最多儲存 \(\frac{N + 1}{2}\)個節點