力扣 99 题 : 力扣
思考二叉搜索树存在中序遍历为升序序列。
如下图: 中序遍历先左结点->根结点->右结点,结合上篇博文
遍历结果应该为 1,2,3。
利用中序遍历的特点,解题思路
1. 中序遍历获取升序列表
2. 找出升序列表中nums[i] > nums[i+1]的位置及值
3. 交换错误数据位置的值。
代码实现
class Solution {
public:
int x;
int y;
// 标记第一次X的位置
bool firstF = true;
void midOrder(vector<int>& nums, TreeNode* root)
{
if (root == nullptr) {
return;
}
midOrder(nums, root->left);
nums.push_back(root->val);
midOrder(nums, root->right);
}
void FindLessPos(vector<int> &nums)
{
for (int i = 0; i < nums.size() - 1; ++i) {
if (nums[i] > nums[i+1]) {
y = nums[i+1];
if (firstF) {
// 因为可能出现两个错误位置在不同的点
// 比如
// 第一种乱序 : 1,3,2,4,5 x = 3, y = 2
// 第二种乱序: 1,5,3,4,2 x = 5; y = 2
x = nums[i];
firstF = false;
}
}
}
}
void Recover(TreeNode* root)
{
if (root == nullptr) {
return;
}
if (root -> val == x) {
root -> val = y;
}else if (root -> val == y) {
root -> val = x;
}
Recover(root->left);
Recover(root->right);
}
void recoverTree(TreeNode* root) {
//利用中序遍历
vector<int> nums;
midOrder(nums, root);
//找到对应的递减的位置;
FindLessPos(nums);
//交换错误的位置
Recover(root);
}
};
该种时间复杂度和空间复杂度都为 O(n);
进阶1
思考,我们可以在中序遍历的过程中就记录下对应的出现差错的位置,利用一个辅助指针pre 记录下前一个结点,根据中序遍历的结果(升序),前面一个结点的值一定小于后面结点的值,所以当发现前一个结点值比当前结点大时,该结点就是又问题的结点,记录下该结点的位置。
代码实现
class Solution {
public:
TreeNode* x1 = nullptr;
TreeNode* y1 = nullptr;
TreeNode* pre = nullptr;
void recoverTree2(TreeNode* root)
{
if (root == nullptr) {
return;
}
recoverTree2(root->left);
if (pre != nullptr && root->val < pre->val) {
y1 = root;
if (x1 == nullptr) {
x1 = pre;
}
}
pre = root;
recoverTree2(root->right);
}
void recoverTree(TreeNode* root) {
recoverTree2(root);
int tmp = x1->val;
x1->val = y1->val;
y1->val = tmp;
}
};
该种方式时间复杂度O(n) 空间复杂度O(h).