Recover Binary Search Tree

update Sep 1, 2017 21:52

LeetCodearrow-up-right

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?

Basic Idea:

思路1( worst one, O(n) space, O(nlogn) time):

虽然是一个比较简单的思路,但一开始我竟没有想出来。就是直接 inorder traverse,把node和val分别存入两个list,对val从小到大排序,然后依次对node list中的node赋值即可。

Python Code:

    class Solution(object):
        def recoverTree(self, root):
            """
            :type root: TreeNode
            :rtype: void Do not return anything, modify root in-place instead.
            """
            def inorder(root):
                if not root: return
                inorder(root.left)
                inorder_nodes.append(root)
                inorder_vals.append(root.val)
                inorder(root.right)

            inorder_nodes = []
            inorder_vals = []
            inorder(root)
            inorder_vals.sort()
            for i in range(len(inorder_nodes)):
                inorder_nodes[i].val = inorder_vals[i]

思路2(O(1) space, O(n) time):

还是那句话,面对一道 hard 难度的题目,给出如上那么 “straight forward” 的解自然交不了差。要做到follow up的要求,我们需要知道一种叫做 Morris-Traversal 算法,这种算法可以实现 O(n) time and O(1) Space 的 Binary Tree Traversing;

这里arrow-up-right 有个关于Morris-Traversal Alg 的介绍;

盗图一张:

精髓就是每到一个节点,通过把它左子树中predecessor的右指针指向自己来实现向上的跟踪;

Python Code: 在实现的过程中,注意对不同的功能部分进行模块化,比如这里,我另外写了一个 visit(prev, node) 函数,这样可以让主要逻辑部分更加简洁易懂。

Java Code:

Note

关于在便利过程中找first和second的方法,灵感来自 这里arrow-up-right; 关键步骤:

Inorder traverse, keep the previous tree node, Find first misplaced node by

Find second by

After traversal, swap the values of first and second node. Only need two pointers, prev and current node. O(1) space.

该方法时间复杂度分析:

因为 Morris Traversal 的过程中我们最多见到每个 node 3 次,所以总的时间复杂度仍然为 O(n);

思路3 (fastest, O(n) time/space)

这种思路最简单,就是直接 inorder 整个树,用方法2中的方法记录fist和second,然后互换值。

update 2018-06-10 15:36:20

Update C++ Solution

增加一种 O(n) 时间,O(logN) 空间的解法,直接inorder遍历,维持一个全局变量prev,和全局变量first and second,其他部分和之前的方法类似,在inorder traversal 的过程中更新 first 和 second,最后 swap。