(64)99. 恢复二叉搜索树(leetcode)

题目链接:
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)

  1. 若x 左指针为空 访问右指针 x=x.right
  2. 若x左指针不为空,找到当前节点左子树的最右节点(该节点为当前节点中序遍历的前驱节点 前驱节点记为(predecessor))
    2.1 如果predecessor的右指针为空,则将右指针指向x;访问x的左指针(即 x=x.left);
    2.2. 如果predecessor的右指针不为空,将predecessor右指针重新置为空(恢复树的原状),并将x置为其右指针(即 x=x.right);
  3. 重复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);
    }
};

Guess you like

Origin blog.csdn.net/li_qw_er/article/details/107873727