[leetcode] 99. Recover Binary Search Tree 解题报告

题目链接:https://leetcode.com/problems/recover-binary-search-tree/

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Note:
A solution using O( n ) space is pretty straight forward. Could you devise a constant space solution?

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.


思路:可以用二叉搜索树的中序遍历实现,这种方式实际上是用了log(n)的空间的,但是对于一个算法来说log(n)算是常量空间了,我曾经专门请教过我们的算法教授.

先来看一个naive的方法,即使用O(n)的空间复杂度应该怎么解决.

我们可以开一个数组,中序遍历树,并将其依次保存在数组中.如果是一个正常的二叉搜索树将会是完全有序的.然而当交换了其中两个结点之后就会出现两个结点出现在错误的位置.举个栗子:[1, 2, 3, 4, 5, 6],这是一个正常的二叉搜索数的序列,当交换了其中两个结点之后变成了[1, 5, 3, 4, 2, 6].

那么如何找到这两个交换的结点呢?我们知道如果一个大的数移到了前面,他必然会比他后面的一个数大,也就是说当我们遍历数组的时候碰到的第一个比后面结点大的结点就是被交换过来的大的结点.那么交换到后面的小的结点也可以用同样的道理找到,即这个小的结点必然比前面一个结点小,但是如果交换的两个结点不是相邻结点的话会有两个结点比前面结点小,因为大的结点交换到前面来他必然比后面一个结点大,然后真正的交换过去的小的结点也会比前面的小.所以我们要找到的是最后一个比前面结点小的结点.

有了上面的理论我们就可以很容易的在数组中找到两个失序的结点了.然后将其值交换就可以了.

好了,既然我们已经知道了使用O(n)空间复杂度的算法了,我们就可以不用将结点保存下来了,因为我们可以直接用中序遍历直接找到这两个结点,但是我们需要一个另外的标记,即当前结点的前一个结点,这样就可以还原上面的算法了.

代码如下:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void inOrder(TreeNode* root)
    {
        if(!root) return;
        inOrder(root->left);
        if(pre && pre->val > root->val)
        {
            if(!first) first = pre;
            second = root;
        }
        pre = root;
        inOrder(root->right);
    }
    
    void recoverTree(TreeNode* root) {
        if(!root) return;
        inOrder(root);
        swap(first->val, second->val);
    }
private:
    TreeNode *pre =NULL, *first =NULL, *second=NULL;
};
参考:不知道哪个博客了

你可能感兴趣的:(leetcode,binary,tree)