【Leetcode】99. 恢复二叉搜索树

QUESTION

hard

题目描述

二叉搜索树中的两个节点被错误地交换

请在不改变其结构的情况下,恢复这棵树

示例 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) 空间复杂度的解法很容易实现
  • 你能想出一个只使用常数空间的解决方案吗?

SOLUTION

一开始我是迷茫的,看到说明里面提示了 O(n) 的空间复杂的,结合BST的性质——中序遍历严格递增,这不就出来了吗!根据提示可以有常数空间来解决这个问题,怎么实现呢?

方法一

按照前面的想法

  • 2n 的空间
  • 中序遍历后,一个 list 存放节点,一个 vals 存放对应的值
  • 这种写法可以适应整个树都错了的一般情况
class Solution {
public:
    void recoverTree(TreeNode* root) {
        vector<TreeNode*> list;
        vector<int> vals;
        inorder(root, list, vals);
        sort(vals.begin(), vals.end());
        for (int i = 0; i < list.size(); ++i) {
            list[i]->val = vals[i];
        }
    }
    void inorder(TreeNode* root, vector<TreeNode*>& list, vector<int>& vals) {
        if (!root) return;
        inorder(root->left, list, vals);
        list.push_back(root);
        vals.push_back(root->val);
        inorder(root->right, list, vals);
    }
};

方法二

其实是方法一的变种

  • 方法一用了 2n 的空间,这里只用了 n
  • 仅适用于两节点出错,即本题的情况
  • 代码有点丑陋,但相比方法一,空间利用率以及效率有略微提升
class Solution {
public:
    void recoverTree(TreeNode* root) {
        vector<TreeNode*> list;
        inorder(root, list);
        int err1 = 0;
        while(err1+1 < list.size() && list[err1]->val < list[err1+1]->val){
            err1++;
        }
        int err2 = err1 + 1;
        while(err2+1 < list.size() && list[err2]->val < list[err2+1]->val){
            err2++;
        }
        if(err2 + 1 >= list.size()) err2 = err1; //遍历到最后都没有异常,故直接err1旁边交换即可
        int tmp = list[err1]->val;
        list[err1]->val = list[err2+1]->val;
        list[err2+1]->val = tmp;
    }
    void inorder(TreeNode* node, vector<TreeNode*>& list){
        if (!node) return;
        inorder(node->left, list);
        list.push_back(node);
        inorder(node->right, list);
    }
};

方法三

Morris遍历,参考博文:http://www.cnblogs.com/grandyang/p/4298069.html

  • 经过测试这个方法效率最高,且完成了进阶的目标
// Now O(1) space complexity
class Solution {
public:
    void recoverTree(TreeNode* root) {
        TreeNode *first = NULL, *second = NULL, *parent = NULL;
        TreeNode *cur, *pre;
        cur = root;
        while (cur) {
            if (!cur->left) {
                if (parent && parent->val > cur->val) {
                    if (!first) first = parent;
                    second = cur;
                }
                parent = cur;
                cur = cur->right;
            } else {
                pre = cur->left;
                while (pre->right && pre->right != cur) pre = pre->right;
                if (!pre->right) {
                    pre->right = cur;
                    cur = cur->left;
                } else {
                    pre->right = NULL;
                    if (parent->val > cur->val) {
                        if (!first) first = parent;
                        second = cur;
                    }
                    parent = cur;
                    cur = cur->right;
                }
            }
        }
        swap(first->val, second->val);
    }
};

你可能感兴趣的:(Leetcode)