Recover Binary Search Tree 题解
题目来源:https://leetcode.com/problems/recover-binary-search-tree/description/
Description
Two elements of a binary search tree (BST) are swapped by mistake.
Recover the tree without changing its structure.
Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?
Solution
解法一:使用递归中序遍历找到乱序节点位置
class Solution {
private:
TreeNode *first = nullptr;
TreeNode *second = nullptr;
TreeNode *pre = nullptr;
void traverse(TreeNode *node) {
if (node) {
traverse(node -> left);
if (!first && pre -> val >= node -> val) // first还没有找到,出现乱序
first = pre;
if (first && pre -> val >= node -> val) // first已经找到,出现乱序
second = node;
pre = node;
traverse(node -> right);
}
}
public:
void recoverTree(TreeNode* root) {
TreeNode temp(INT_MIN);
pre = &temp;
traverse(root);
swap(first -> val, second -> val);
}
};
解法二:使用Morris中序遍历找到乱序节点位置
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode *first = NULL;
TreeNode *second = NULL;
TreeNode *pre = NULL;
TreeNode *temp = NULL;
// Morris遍历
while (root) {
if (root -> left) {
temp = root -> left;
while (temp -> right && temp -> right != root) {
// 找到左子树的最右节点
temp = temp -> right;
}
if (temp -> right) { // 左子树的最右节点已经连接到pre的左侧
if (pre && pre -> val >= root -> val) {
if (!first) {
first = pre;
// 因为可能只存在一个乱序位置,所以要先设置second
second = root;
} else {
second = root;
}
}
// 左子树已经遍历
pre = root; // 右子树之前访问的点即为root
temp -> right = NULL; // 断开左子树最右侧节点与root的连接
root = root -> right; // 切换到右子树进行遍历
} else { // 仍未连接到pre,则进行连接
temp -> right = root; // 将左子树最右侧节点与root连接
root = root -> left; // 左子树还没遍历,切换到左子树进行遍历
}
} else {
// 左子树为空的情况
if (pre && pre -> val >= root -> val) {
if (!first) {
first = pre;
second = root;
} else {
second = root;
}
}
// 左子树为空,切换到右子树
pre = root; // 右子树之前访问的点即为root
root = root -> right; // 切换到右子树进行遍历
}
}
if (first && second)
swap(first -> val, second -> val);
}
};
解题描述
这道题题意是,给出一棵二叉搜索树,树上有两个节点被交换了位置,要求恢复这棵二叉搜索树。上面给出两种解法,分别是递归中序遍历解法和Morris中序遍历的解法。其中Morris中序遍历是一种非递归的树遍历方式,并且不需要借助队列或者栈等数据结构,具有常数空间复杂度。