Hard!
題目描述:
二叉搜索樹中的兩個節點被錯誤地交換。
請在不改變其結構的情況下,恢復這棵樹。
示例 1:
輸入: [1,3,null,null,2] 1 / 3 \ 2 輸出: [3,1,null,null,2] 3 / 1 \ 2
示例 2:
輸入: [3,1,4,null,null,2] 3 / \ 1 4 / 2 輸出: [2,1,4,null,null,3] 2 / \ 1 4 / 3
進階:
- 使用 O(n) 空間復雜度的解法很容易實現。
- 你能想出一個只使用常數空間的解決方案嗎?
解題思路:
這道題要求我們復原一個二叉搜索樹,說是其中有兩個的順序被調換了,題目要求上說O(n)的解法很直觀,這種解法需要用到遞歸,用中序遍歷樹,並將所有節點存到一個一維向量中,把所有節點值存到另一個一維向量中,然后對存節點值的一維向量排序,再將排好的數組按順序賦給節點。這種最一般的解法可針對任意個數目的節點錯亂的情況。
C++解法一:
1 // O(n) space complexity 2 class Solution { 3 public: 4 void recoverTree(TreeNode *root) { 5 vector<TreeNode*> list; 6 vector<int> vals; 7 inorder(root, list, vals); 8 sort(vals.begin(), vals.end()); 9 for (int i = 0; i < list.size(); ++i) { 10 list[i]->val = vals[i]; 11 } 12 } 13 void inorder(TreeNode *root, vector<TreeNode*> &list, vector<int> &vals) { 14 if (!root) return; 15 inorder(root->left, list, vals); 16 list.push_back(root); 17 vals.push_back(root->val); 18 inorder(root->right, list, vals); 19 } 20 };
然后我上網搜了許多其他解法,看到另一種是用雙指針來代替一維向量的,但是這種方法用到了遞歸,也不是O(1)空間復雜度的解法,這里需要三個指針,first,second分別表示第一個和第二個錯亂位置的節點,pre指向當前節點的中序遍歷的前一個節點。這里用傳統的中序遍歷遞歸來做,不過再應該輸出節點值的地方,換成了判斷pre和當前節點值的大小,如果pre的大,若first為空,則將first指向pre指的節點,把second指向當前節點。這樣中序遍歷完整個樹,若first和second都存在,則交換它們的節點值即可。這個算法的空間復雜度仍為O(n),n為樹的高度。
C++解法二:
1 // Still O(n) space complexity 2 class Solution { 3 public: 4 TreeNode *pre; 5 TreeNode *first; 6 TreeNode *second; 7 void recoverTree(TreeNode *root) { 8 pre = NULL; 9 first = NULL; 10 second = NULL; 11 inorder(root); 12 if (first && second) swap(first->val, second->val); 13 } 14 void inorder(TreeNode *root) { 15 if (!root) return; 16 inorder(root->left); 17 if (!pre) pre = root; 18 else { 19 if (pre->val > root->val) { 20 if (!first) first = pre; 21 second = root; 22 } 23 pre = root; 24 } 25 inorder(root->right); 26 } 27 };
道題的真正符合要求的解法應該用的Morris遍歷,這是一種非遞歸且不使用棧,空間復雜度為O(1)的遍歷方法,可參見我之前的博客Binary Tree Inorder Traversal 二叉樹的中序遍歷,在其基礎上做些修改,加入first, second和parent指針,來比較當前節點值和中序遍歷的前一節點值的大小,跟上面遞歸算法的思路相似。
C++解法三:
1 // Now O(1) space complexity 2 class Solution { 3 public: 4 void recoverTree(TreeNode *root) { 5 TreeNode *first = NULL, *second = NULL, *parent = NULL; 6 TreeNode *cur, *pre; 7 cur = root; 8 while (cur) { 9 if (!cur->left) { 10 if (parent && parent->val > cur->val) { 11 if (!first) first = parent; 12 second = cur; 13 } 14 parent = cur; 15 cur = cur->right; 16 } else { 17 pre = cur->left; 18 while (pre->right && pre->right != cur) pre = pre->right; 19 if (!pre->right) { 20 pre->right = cur; 21 cur = cur->left; 22 } else { 23 pre->right = NULL; 24 if (parent->val > cur->val) { 25 if (!first) first = parent; 26 second = cur; 27 } 28 parent = cur; 29 cur = cur->right; 30 } 31 } 32 } 33 if (first && second) swap(first->val, second->val); 34 } 35 };