题目链接:
https://leetcode-cn.com/problems/recover-binary-search-tree/
难度:困难
99. 恢复二叉搜索树
二叉搜索树中的两个节点被错误地交换。
请在不改变其结构的情况下,恢复这棵树。
示例 1:
输入: [1,3,null,null,2]
1
/
3
\
2
输出: [3,1,null,null,2]
3
/
1
\
2
示例 2:
输入: [3,1,4,null,null,2]
3
/ \
1 4
/
2
输出: [2,1,4,null,null,3]
2
/ \
1 4
/
3
进阶:
使用 O(n) 空间复杂度的解法很容易实现。
你能想出一个只使用常数空间的解决方案吗?
困难题 这个题目 还行吧 有思路 不过一直有个问题:到底有没有或者说是否允许重复的键 题解中没有说。。 可能是默认没有 也可能是无影响
写的时候犯了一个错误 可能是困了?。。。 我没有必要交换节点 只需要交换值 就可以了 其它的没有什么问题了(废了1个小时的时间 就写了个和题解中最简单的方法一样 的代码。。。 哎)
(我感觉默认的是不会有重复键的)
1. 中序遍历 2. 存放到数组 3. 查找出交换的值 4. 中序遍历找到需要交换的进行赋值 (困了 注释不写了 我应该看的懂)
/**
* 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 {
public:
vector<int> vec;
void getVec(TreeNode* r){
if(r==nullptr){
return;
}
getVec(r->left);
vec.push_back(r->val);
getVec(r->right);
}
void swap(TreeNode *r,int x,int y,int count){
if(r==nullptr){
return;
}
if(r->val==x||r->val==y){
r->val=(r->val==x)?y:x;
if(--count==0){
return;
}
}
swap(r->left,x,y,count);
swap(r->right,x,y,count);
}
void recoverTree(TreeNode* root) {
getVec(root);
int x=-1,y=-1;
for(int i=0;i<vec.size()-1;++i){
if(vec.at(i)>vec.at(i+1)){
y=vec.at(i+1);
if(x==-1){
x=vec.at(i);
}else{
break;
}
}
}
swap(root,x,y,2);
}
};
和上个思路一样 中序遍历使用迭代
class Solution {
public:
void recoverTree(TreeNode* root) {
stack<TreeNode*> stk;
TreeNode* x=nullptr;
TreeNode* y=nullptr;
TreeNode* pre=nullptr;
TreeNode* cur=root;
while(!stk.empty()||cur!=nullptr){
while(cur!=nullptr){
stk.push(cur);
cur=cur->left;
}
cur=stk.top();
stk.pop();
if(pre!=nullptr&&pre->val>cur->val){
y=cur;
if(x==nullptr){
x=pre;
}else{
break;
}
}
pre=cur;
cur=cur->right;
}
swap(x->val,y->val);
}
};
Morris 遍历算法 (emmm… 第一次听说)
算法: (假设当前节点为x)
- 若x 左指针为空 访问右指针 x=x.right
- 若x左指针不为空,找到当前节点左子树的最右节点(该节点为当前节点中序遍历的前驱节点 前驱节点记为(predecessor))
2.1 如果predecessor的右指针为空,则将右指针指向x;访问x的左指针(即 x=x.left);
2.2. 如果predecessor的右指针不为空,将predecessor右指针重新置为空(恢复树的原状),并将x置为其右指针(即 x=x.right); - 重复1~2,直到当前节点为空。
感觉这个写代码 不难写 关键是我不知道为什么。。。。 算了 困了 以后再说
class Solution {
public:
void recoverTree(TreeNode* root) {
stack<TreeNode*> stk;
TreeNode* x=nullptr;
TreeNode* y=nullptr;
TreeNode* pre=nullptr;
TreeNode* cur=root;
TreeNode* predecessor=nullptr;
while(cur!=nullptr){
if(cur->left!=nullptr){
predecessor=cur->left;
while(predecessor->right!=nullptr&&predecessor->right!=cur){
predecessor=predecessor->right;
}
if(predecessor->right==nullptr){
predecessor->right=cur;
cur=cur->left;
}else{
if(pre!=nullptr&&pre->val>cur->val){
y=cur;
if(x==nullptr){
x=pre;
}
}
pre=cur;
cur=cur->right;
predecessor->right = nullptr;
}
}else{
if(pre!=nullptr&&pre->val>cur->val){
y=cur;
if(x==nullptr){
x=pre;
}
}
pre=cur;
cur=cur->right;
}
}
swap(x->val,y->val);
}
};