99. 恢复二叉搜索树

给你二叉搜索树的根节点 root ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用常数空间的解决方案吗?莫里斯,难

思路一

时间复杂度O(n),n是节点个数,空间复杂度O(H),递归栈的深度

中序遍历BST,依次访问的节点值是递增的,错误的BST会破坏递增性,从而能定位出错误。
我发现,错误有两种:

  • 错误1:出现了两对不满足前小后大,需要交换第一对的第一个元素与第二对的第二个元素。
  • 错误2:只出现一对不满足前小后大,交换这一对元素即可。

99. 恢复二叉搜索树 难 - 图1
可以在的递归遍历过程中,将节点值推入一个数组,再遍历数组找出错误对。
但其实没必要。
只用比较前后访问的节点值,prev 保存上一个访问的节点,当前访问的是 root 节点。
每访问一个节点,如果prev.val>=root.val,就找到了一对“错误对”。
检查一下它是第一对错误对,还是第二对错误对。
遍历结束,就确定了待交换的两个错误点,进行交换。

  1. func recoverTree(root *TreeNode) {
  2. pre := &TreeNode{Val : math.MinInt32 - 1}
  3. var err1 , err2 *TreeNode //1,两种错误情况
  4. var inorder func(root *TreeNode)
  5. inorder = func(root *TreeNode) {
  6. if root == nil {
  7. return
  8. }
  9. inorder(root.Left)
  10. if pre.Val >= root.Val && err1 == nil {
  11. err1 = pre
  12. }
  13. if pre.Val >= root.Val && err1 != nil {
  14. err2 = root
  15. }
  16. pre = root
  17. inorder(root.Right)
  18. }
  19. inorder(root)
  20. err1.Val, err2.Val = err2.Val, err1.Val
  21. }
//中序递归,时空On
var last,first, second *TreeNode

func recoverTree(root *TreeNode) {
    last, first, second = nil, nil, nil
    dfs(root)
    first.Val, second.Val = second.Val, first.Val
}

func dfs(root *TreeNode) {
    if root == nil {
        return
    }
    dfs(root.Left)
    if last != nil && root.Val <= last.Val {
        if first != nil {
            second = root
            return //剪枝
        }
        first, second = last, root
    }
    last = root
    dfs(root.Right)
}
//莫里斯,时间On,空间O1,无敌!
func recoverTree(root *TreeNode) {
    var last, first, second, max *TreeNode
    for root != nil {
        if root.Left == nil {
            if last != nil && root.Val <= last.Val {
                if first == nil {
                    first = last
                }
                second = root
            }
            last = root
            root = root.Right
        } else {
            //寻找左树最大节点
            max = root.Left
            for max.Right != nil && max.Right != root {
                max = max.Right
            }

            if max.Right != root {
                // 未连接,连接到root
                max.Right = root
                root = root.Left
            } else {
                // 已连接,断开连接
                max.Right = nil
                if last != nil && root.Val <= last.Val {
                    if first == nil {
                        first = last
                    }
                    second = root
                }
                last = root
                root = root.Right
            }
        }
    }
    first.Val, second.Val = second.Val, first.Val
}