一棵二叉搜索樹(BST)中有兩個節點被錯誤交換,請恢復樹的正確結構。要求常數空間(遞歸棧不算)。
若兩個節點交換,中序序列會出現「逆序對」:
prev.val > curr.val。交換這兩個節點即可。prev(較大值)和第二處的 curr(較小值)是被交換的兩個節點。遞歸/棧遍歷空間 O(h)。Morris 遍歷利用葉節點的空指針建立線索,無需額外空間。
class Solution:
def __init__(self):
self.first = self.second = self.prev = None
def recoverTree(self, root):
self._inorder(root)
self.first.val, self.second.val = self.second.val, self.first.val
def _inorder(self, node):
if not node: return
self._inorder(node.left)
if self.prev and node.val < self.prev.val:
if not self.first: # 第一處逆序
self.first = self.prev
self.second = node # 最後一處逆序的 curr
self.prev = node
self._inorder(node.right)
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode *first = nullptr, *second = nullptr, *prev = nullptr, *cur = root;
while (cur) {
if (!cur->left) {
// 訪問 cur
if (prev && cur->val < prev->val) {
if (!first) first = prev;
second = cur;
}
prev = cur;
cur = cur->right;
} else {
// 找前驅
TreeNode* pre = cur->left;
while (pre->right && pre->right != cur) pre = pre->right;
if (!pre->right) {
pre->right = cur; // 建立線索
cur = cur->left;
} else {
pre->right = nullptr; // 恢復樹
// 訪問 cur
if (prev && cur->val < prev->val) {
if (!first) first = prev;
second = cur;
}
prev = cur;
cur = cur->right;
}
}
}
swap(first->val, second->val);
}
};
first = 第一處的 prev, second = 最後一處的 curr。