输入: 二叉搜索树根节点 root,其中恰好有两个节点的值被错误交换。
要求: 在不改变树结构的情况下恢复 BST(只允许改节点值)。
输出: 无(原地修改 root)。
思路:
BST 的中序遍历应该是严格递增序列。
一旦有两个节点值被交换,中序序列里就会出现“乱序”,表现为 逆序对:
- 正常:
... a < b < c < d ... - 交换后可能出现:
- 相邻交换:只出现 1 次 逆序(例如
... a < c < b < d ...,在c > b处逆序) - 不相邻交换:出现 2 次 逆序(例如
... a < d < c < b ...,会在d > c、c > b两处逆序)
- 相邻交换:只出现 1 次 逆序(例如
所以我们中序遍历时维护 prev(上一个访问的节点):
- 若发现
prev->val > node->val,说明出现逆序。 - 第一次逆序:
first = prev(大的那个) - 每次逆序都更新
second = node(小的那个)- 相邻交换:只会更新一次
second - 不相邻交换:第二次逆序会把
second更新成最终正确的小节点
- 相邻交换:只会更新一次
遍历结束后交换 first 和 second 的值即可恢复。
复杂度:
- 时间复杂度:O(N)
- 空间复杂度:O(H)(递归栈,H 为树高)
class Solution {
public:
void recoverTree(TreeNode* root) {
first = nullptr;
second = nullptr;
prev = nullptr;
inorder(root);
if (first != nullptr && second != nullptr) {
int tmp = first->val;
first->val = second->val;
second->val = tmp;
}
}
private:
TreeNode* first;
TreeNode* second;
TreeNode* prev;
void inorder(TreeNode* node) {
if (node == nullptr) return;
inorder(node->left);
if (prev != nullptr && prev->val > node->val) {
if (first == nullptr) first = prev;
second = node;
}
prev = node;
inorder(node->right);
}
};
832

被折叠的 条评论
为什么被折叠?



