99.恢复二叉搜索树

99.恢复二叉搜索树

二叉搜索树中的两个节点被错误地交换。
请在不改变其结构的情况下,恢复这棵树

1.dfs分情况讨论

左子树最大值与右子树最小值交换
左子树最大值与根节点交换
右子树最小值与根节点交换
左子树两个节点互换
右子树两个节点互换

class Solution {
public:
    void maxNode(TreeNode* root,TreeNode* &big)
    {
        if(!root)return;
        if(root->val>big->val)
        {
            big = root;
        }
        maxNode(root->left,big);
        maxNode(root->right,big);
    }
    void minNode(TreeNode* root,TreeNode* &small)
    {
        if(!root)return;
        if(root->val<small->val)
        {
            small = root;
        }
        minNode(root->left,small);
        minNode(root->right,small);
    }
    void recoverTree(TreeNode* root) {
       if(!root)return;
       TreeNode* left = root->left;
       TreeNode*right = root->right;
       maxNode(root->left,left);
       minNode(root->right,right);
       if(left!=NULL && right!=NULL && left->val>root->val && root->val>right->val)
       {
           int temp;
           temp = right->val;
           right->val = left->val;
           left->val = temp;
       }
       else if(left!=NULL && left->val>root->val)
       {
           int temp;
           temp = root->val;
           root->val = left->val;
           left->val = temp;
       }
       else if(right!=NULL && right->val<root->val)
       {
           int temp;
           temp = root->val;
           root->val = right->val;
           right->val = temp;
       }
       recoverTree(root->left);
       recoverTree(root->right);

    }
};

2.显示中序遍历,用数据结构保存,找出大小不符合的元素

(dfs或bfs)

class Solution {
public:
    void inorder(TreeNode* root, vector<int>& nums) {
        if (root == nullptr) {
            return;
        }
        inorder(root->left, nums);
        nums.push_back(root->val);
        inorder(root->right, nums);
    }

    pair<int,int> findTwoSwapped(vector<int>& nums) {
        int n = nums.size();
        int x = -1, y = -1;
        for(int i = 0; i < n - 1; ++i) {
            if (nums[i + 1] < nums[i]) {
                y = nums[i + 1];
                if (x == -1) {
                    x = nums[i];
                }
                else break;
            }
        }
        return {x, y};
    }
    
    void recover(TreeNode* r, int count, int x, int y) {
        if (r != nullptr) {
            if (r->val == x || r->val == y) {
                r->val = r->val == x ? y : x;
                if (--count == 0) {
                    return;
                }
            }
            recover(r->left, count, x, y);
            recover(r->right, count, x, y);
        }
    }

    void recoverTree(TreeNode* root) {
        vector<int> nums;
        inorder(root, nums);
        pair<int,int> swapped= findTwoSwapped(nums);
        recover(root, 2, swapped.first, swapped.second);
    }
};

3.隐式中序遍历,用pre指针保存上一个节点,当发现大小不符合时互换

(dfs或bfs)

class Solution {
public:
    void recoverTree(TreeNode* root) {
       if(!root)return;
        stack<TreeNode*> stk;
        TreeNode* x = NULL;
        TreeNode* y = NULL;
        TreeNode* pred =  NULL;
        while(root!=NULL || !stk.empty())
        {
            while(root!=NULL)
            {
                stk.push(root);
                root = root->left;
            }
            root = stk.top();
            stk.pop();
            if (pred != nullptr && root->val < pred->val) {
                y = root;
                if (x == nullptr) {
                    x = pred;
                }
                else break;
            }
            pred = root;
            root = root->right;
        }
        swap(y->val,x->val);

    }
};

莫里斯遍历

将当前节点左子树中最右边的节点指向它,这样在左子树遍历完成后我们通过这个指向走回了 xx,且能再通过这个知晓我们已经遍历完成了左子树,而不用再通过栈来维护,省去了栈的空间复杂度。
保证空间复杂度O(1)

class Solution {
public:
    void recoverTree(TreeNode* root) {
        TreeNode *x = nullptr, *y = nullptr, *pred = nullptr, *predecessor = nullptr;

        while (root != nullptr) {
            if (root->left != nullptr) {
                // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
                predecessor = root->left;
                while (predecessor->right != nullptr && predecessor->right != root) {
                    predecessor = predecessor->right;
                }
                
                // 让 predecessor 的右指针指向 root,继续遍历左子树
                if (predecessor->right == nullptr) {
                    predecessor->right = root;
                    root = root->left;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    if (pred != nullptr && root->val < pred->val) {
                        y = root;
                        if (x == nullptr) {
                            x = pred;
                        }
                    }
                    pred = root;

                    predecessor->right = nullptr;
                    root = root->right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                if (pred != nullptr && root->val < pred->val) {
                    y = root;
                    if (x == nullptr) {
                        x = pred;
                    }
                }
                pred = root;
                root = root->right;
            }
        }
        swap(x->val, y->val);
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值