LeetCode - 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?

这道题是利用BST的规律,inorder traversal的话会返回一个从小到大的list,这时候逆序的就是被交换的。

12345678,交换后 12543678,由于把大数交换到前面,所以第一个逆序的肯定是比它后面的数大的,如果是相邻两个数交换的话,只需要把逆序的数和它后面的数交换就行,如果不是相邻的数的话,第二个逆序肯定是比它前面的数小的,可以看到例子中4,3都比前面的数小,取遇到的最后一个就可以了。

public class Solution {
    private TreeNode previous;
    private TreeNode abnormal1;
    private TreeNode abnormal2;
    
    public void recoverTree(TreeNode root) {
        inorder(root);
        int tmp = abnormal1.val;
        abnormal1.val = abnormal2.val;
        abnormal2.val = tmp;
    }
    public void inorder(TreeNode root){
        if(root==null ) return;
        inorder(root.left);
        if(previous!=null && root.val < previous.val){
            if(abnormal1==null){
                abnormal1 = previous;
                abnormal2 = root;
            }
            else abnormal2 = root;
        }
        previous = root;
        inorder(root.right);
    }
}
这种方法时间复杂度O(n),空间复杂度是递归栈所用的空间O(lgn)

空间复杂度O(1)的解法的解释见这里:http://fisherlei.blogspot.com/2012/12/leetcode-recover-binary-search-tree.html

如何用O(1)空间进行Inorder Tree Traversal:

重点就是一个节点的前一个几点是它左子树的最右节点,于是每次如果有左子树,则找到最右节点,把最右节点的右指针(因为是最右节点,所以一开始肯定为空)指向这个节点,于是当遍历到最右节点时,就可以回到这个节点了。

另外,当发现最右节点的右指针已经指向该节点时,说明左子树已经完全访问过了,于是此时就访问当前节点,然后右子树就可以了。

时间复杂度O(n*lgn),因为此时每个节点都需要去找它左子树的最右节点,which is O(lgn)

    public void recoverTree(TreeNode root) {
        if(root==null) return;
        TreeNode pre = null;
        TreeNode ab1 = null;
        TreeNode ab2 = null;
        TreeNode current = root;
        while(current!=null){
            if(current.left==null){
                if(pre!=null && pre.val>current.val){
                    if(ab1==null){
                        ab1 = pre;
                    }
                    ab2 = current;
                }
                pre = current;
                current = current.right;
            }
            else{
                TreeNode left = current.left;
                while(left.right!=null && left.right!=current){
                    left = left.right;
                }
                if(left.right==current){
                    if(pre!=null && pre.val>current.val){
                        if(ab1==null){
                            ab1 = pre;
                        }
                        ab2 = current;
                    }
                    pre = current;
                    current = current.right;
                    left.right = null;
                }
                else{
                    left.right = current;
                    current = current.left;
                }
                
            }
        }
        int tmp = ab1.val;
        ab1.val = ab2.val;
        ab2.val = tmp;
    }




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值