[leetcode] 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?

根据“BST的中序遍历是有序的”这一特征,就有如下两种情况值得考虑:

1   如果出现交换的两个数是相邻的

如:1 2 3 4 5 6 7,交换 2和3,得到 1  3  2  4  5  6  7 ,也就是说在交换之后形成的二叉树中会出现一对“反常”的数,如本例中的(3,2)

2 如果出现交换的数不是相邻的

如: 1 2 3  4 5 6 7    ,交换 2 和5 ,得到 1  5  3  4  2  6  7 ,也就是说在交换之后会有两对“反常”的数,如本例中的(5,3)和(4,2).

思路 1:使用中序遍历的非递归实现,利用栈可得到:

    void recoverTree(TreeNode *root) {
        if(root == NULL)return;
        stack< TreeNode *> s1;
        TreeNode *node1 = NULL;
        TreeNode *node2 = NULL;
        TreeNode *pre = NULL;

        while(root || !s1.empty())
        {
            while(root)
            {
                s1.push(root);
                root = root->left;
                continue;
            }
            root = s1.top();
            s1.pop();
            
            if(pre && ( root->val < pre->val) )
            {
                if(node1 == NULL) node1 = pre; //当前值比后面的值大,那么pre一定是node1,root有可能是node2。因此必须将node2的值保存下来,如果再次遇到pre>root的情况的时候,那么现在的root就一定是node2.
                //如果没有再次遇到pre>root的话,那么说明是相邻的两个节点出现了交换。
                node2 = root;
            }
            pre = root;
            root = root->right;
        }
        swap(node1->val,node2->val);
        return;
    }
关于上述两种情况的说明,已经在程序中注释证明了。时间复杂度为O(n).

由于我每一次只需要与前驱节点进行比较,因此使用Morris遍历,可将时间复杂度降低到O(1)。关于Morris中序遍历,参见Morris中序遍历,以及线索二叉树

2   采用中序遍历的常数空间的版本。代码如下:

    void recoverTree(TreeNode *root) {
        if(root == NULL)return;
        TreeNode *ch1(NULL);
        TreeNode *ch2(NULL);
        TreeNode *pre(NULL);
        
        while(root)
        {
            if(root->left == NULL)
            {
                if(pre && pre->val > root->val)
                {
                    if(ch1 == NULL) ch1 = pre;
                    ch2 = root;
                }
                pre = root;
                root = root->right;
                continue;
            }
            TreeNode *temp = root->left;
            for(;temp->right && temp->right != root; temp = temp->right);
            if(temp->right == NULL)
            {
                temp->right = root;
                root = root->left;
            }
            else
            {
                if(pre && pre->val > root->val)
                {
                    if(ch1 == NULL) ch1 = pre;
                    ch2 = root;
                }
                temp->right = NULL;
                pre = root;
                root = root->right;
            }
        }
        swap(ch1->val,ch2->val);
        return ;
    }
本题的难点应该在于,如果交换的是相邻的节点,那么只会出现一对反常的数。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值