leetcode:99. 恢复二叉搜索树
题目
给你二叉搜索树的根节点 root
,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。
示例 1:
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。
示例 2:
输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用 O(1) 空间的解决方案吗?
解答 & 代码
解法一:递归中序遍历,空间复杂度 O(logN)
二叉搜索树的中序遍历序列是递增序列,本题的二叉搜索树中有两个节点的值错位,则说明中序遍历序列中有两个元素的位置被交换,使得序列不再有序。
交换递增序列的两个位置,存在两种情况:设有序序列 [1, 2, 3, 4, 5]
- 交换相邻的两个元素:eg. 交换 2、3,则序列变为
[1, **3, 2**, 4, 5]
- 则序列中只存在一处
nums[i] < nums[i+1]
的情况
- 交换不相邻的两个元素:eg. 交换 2、5,则序列变为
[1, **5****, 3**, **4, ****2**]
- 则序列中存在两处
nums[i] < nums[i+1]
的情况
记录两个待交换的错位节点,再交换即可
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
TreeNode* wrongNode1; // 第一个错位节点
TreeNode* wrongNode2; // 第二个错位节点
TreeNode* pre; // 中序遍历前一个节点
// 中序遍历,寻找两个错位节点
void inOederFindWrongNodes(TreeNode* root)
{
if(root == nullptr)
return;
// 递归遍历左子树
if(root->left)
inOederFindWrongNodes(root->left);
// 中序遍历位置:找出两个错位节点
if(root->val < pre->val) // 若 root 的值小于中序前一个节点 pre 的值
{
if(wrongNode1 == nullptr) // 若 wrongNode1 为空,则 pre 是第一个错位节点
wrongNode1 = pre;
wrongNode2 = root; // root 是第二个错位节点
}
pre = root; // 更新中序遍历序列的 pre 节点为 root
// 递归遍历右子树
if(root->right)
inOederFindWrongNodes(root->right);
}
public:
void recoverTree(TreeNode* root) {
wrongNode1 = nullptr;
wrongNode2 = nullptr;
pre = new TreeNode(INT_MIN);
// 中序遍历,寻找两个错位节点
inOederFindWrongNodes(root);
// 交换两个错为节点的值
int temp = wrongNode1->val;
wrongNode1->val = wrongNode2->val;
wrongNode2->val = temp;
}
};
复杂度分析:设二叉搜索树的节点数为 N
- 时间复杂度 O(N):中序遍历二叉树所有节点
- 空间复杂度 O(log N):递归栈深度 = 二叉树深度
执行结果:
执行结果:通过
执行用时:32 ms, 在所有 C++ 提交中击败了 41.09% 的用户
内存消耗:56.2 MB, 在所有 C++ 提交中击败了 88.90% 的用户
解法二:Morris 遍历,空间复杂度 O(1)
本题的进阶要求空间复杂度 O(1),因此需要使用 Morris 遍历