99-Recover-Binary-Search-Tree

原题链接

0x0 题目详情

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

进阶: 使用 O(n) 空间复杂度的解法很容易实现。 你能想出一个只使用常数空间的解决方案吗?

0x1 解题思路

这道题如果使用常规的中序遍历去做的话,无论是迭代版本还是递归版本,都会产生O(N)的空间复杂度。当然常规方法其中有一点我没有想到的就是会产生一组逆序对或者两组逆序对(因为这道题限制了只有两个数出现错误,所以至多只会出现两组),单纯的找出一组逆序对不太行。产生两组逆序对的情况就是这三个数(两组逆序对)的首尾需要交换。比如3、2、1这种情况。当然出现一组逆序对就直接交换就好了。

正确做法应该是采用morris遍历,空间复杂度为O(1),因为这种方法的遍历不再需要空间记录回溯的位置,会利用空闲的右指针来记录。morris遍历说来也简单,就是如果一颗树有左子树,那么我们需要找到该左子树的最右节点,此时一定为null,将其指向当前树的根节点后继续遍历左子树,如果没有左子树,那么直接遍历右子树。

采用上述的方法,如果一个节点有左子树,那么最后一定会来到该节点两次,第二次是通过先前设置的左子树的最右节点到达。代码实现也非常简单(Morris遍历是不需要递归的)。

``` java "Morris的简单遍历" class TreeNode{ TreeNode left; TreeNode right; int val; }

void Morris(TreeNode root){ TreeNode cur=root; TreeNode most_right=null;

while(cur != null){
    most_right=cur.left;
    if(most_right!=null){
        while(most_right!=null && most_right!=cur){
            //找到左子树的最右节点
            most_right=most_right.right;
        }
        if(most_right == null){
            //首次将最右指针指向当前节点
            most_right.right=cur;
            cur=cur.left;
            continue;
        }else{
            //第二次遇到最右指针了,就需要把它恢复成null
            most_right.right=null;
        }
    }
    //已经没有左子树了,直接走向右子树就可

    cur=cur.right;
}

}

ok,前序遍历已经完成了,还是挺简单的。

中序遍历

这棵树的中序遍历结果为10、8、1、9、3、6、2、11。从morris遍历里中,如果一个节点能遍历两边,那么我们只用取第二遍,如果一个节点只能遍历一次,那么肯定也只取这一次了。

``` java "Morris中序遍历" class TreeNode{ TreeNode left; TreeNode right; int val; }

void Morris(TreeNode root){ TreeNode cur=root; TreeNode most_right=null;

}

0x2 代码实现

有了上面的基础,我们就很容易写出空间复杂度为O(1)的中序遍历。

0x3 课后总结

怎么说呢,BST就是中序遍历关系很紧密,Morris遍历只适用于不需要从左树、右树获取信息然后再决定当前如何操作的情况。

Last updated

Was this helpful?