99. Recover Binary Search Tree

Description

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Example 1:

Input: [1,3,null,null,2]

image.png

Output: [3,1,null,null,2]
image.png

Example 2:

Input: [3,1,4,null,null,2]

image.png

Output: [2,1,4,null,null,3]
image.png

Follow up:

  • A solution using O(n) space is pretty straight forward.
  • Could you devise a constant space solution?

Solution

Inorder recursion, time O(n), space O(n)

题意还是很明了的,将BST序列化成inorder形式,然后找到两个in disorder的位置交换即可。需要注意的是,可能会有多个节点in disorder,我们需要找到第一个和最后一个in disorder的位置

考虑这个test case: inorder为{1, 2, 3, 4, 5, 6}
交换2和5变成:{1, 5, 3, 4, 2, 6}
交换之后,{5, 3, 4, 2}都不合规矩(即不满足a[i - 1] < a[i] < a[i + 1]),我们只需要交换5和2即可。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public void recoverTree(TreeNode root) {
        List list = new ArrayList<>();
        inorder(root, list);
        
        int first = -1;
        int second = -1;
        
        for (int i = 0; i < list.size(); ++i) {
            if (first < 0 && isDisorder(list, i)) {
                first = i;
            } else if (first >= 0 && isDisorder(list, i)) {
                second = i;
            }
        }
        
        if (second > 0) {
            swap(list, first, second);
        }
    }
    
    public void inorder(TreeNode root, List list) {
        if (root == null) {
            return;
        }
        
        inorder(root.left, list);
        list.add(root);
        inorder(root.right, list);
    }
    
    public boolean isDisorder(List list, int i) {
        return (i > 0 && list.get(i).val < list.get(i - 1).val)
            || (i < list.size() - 1 && list.get(i).val > list.get(i + 1).val);
    }
    
    public void swap(List list, int i, int j) {
        int tmp = list.get(i).val;
        list.get(i).val = list.get(j).val;
        list.get(j).val = tmp;
    }
}

Inorder recursion, time O(n), space O(h)

添加几个成员变量即可。需要注意first和second的值可能会在同一层被更新(考虑inorder遍历的相邻节点被swap),inorder中需要有两个if条件,而非一个if-else。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode first;
    private TreeNode second;
    private TreeNode pre = new TreeNode(Integer.MIN_VALUE);
    
    public void recoverTree(TreeNode root) {
        inorder(root);
        swap(first, second);
    }
    
    public void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        
        inorder(root.left);

        if (first == null && root.val < pre.val) {
            first = pre;    // first should be the first element in disorder
        }
        
        if (first != null && root.val < pre.val) {  // another independent condition
            second = root;  // second should be the last element in disorder
        }
        
        pre = root;
        
        inorder(root.right);
    }
    
    public void swap(TreeNode p, TreeNode q) {
        int tmp = p.val;
        p.val = q.val;
        q.val = tmp;
    }
}

Morris traversal, time O(n), space O(1)

由于一旦涉及递归,就不可能达到O(1)的空间复杂度。想要降低消耗,就必须用神奇的Morris traversal啦(which 我不会写也懒得学学了也会忘)。

你可能感兴趣的:(99. Recover Binary Search Tree)