Reference: LeetCode
Difficulty: Hard
Problem
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] |
1 | Input: [3,1,4,null,null,2] |
Follow up:
- A solution using $O(N)$ space is pretty straightforward. Could you devise a constant space solution?
Analysis
Methods:
Sort An Almost Sorted Array
- Construct inorder traversal of the tree. It should be an almost sorted list where
only two elements are swapped. - Identify two swapped elements
xandyin an almost sorted array.- The algorithm assumes that there is only one inversion which allows cases like:
[3 2 1 4](it can’t be[3 2 1 0]since it needs more than one swapping)[2 1 3 4]
- So, we update
y = nums.get(i + 1)first for two times if necessary, and updatex = nums.get(i)only once in the first time.
- The algorithm assumes that there is only one inversion which allows cases like:
- Traverse the tree again and swap
xandy.
Time: $O(N)$ since we apply traversals.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52public void recoverTree(TreeNode root) {
List<Integer> nums = new ArrayList<>();
inorder(root, nums);
int[] swapXY = findTwoSwapped(nums);
inorderSwap(root, 2, swapXY[0], swapXY[1]);
}
// inorder
private void inorder(TreeNode root, List<Integer> nums) {
if (root == null) {
return;
}
inorder(root.left, nums);
nums.add(root.val);
inorder(root.right, nums);
}
// find two swapped
private int[] findTwoSwapped(List<Integer> nums) {
int n = nums.size();
Integer x = null, y = null;
for (int i = 0; i < n - 1; ++i) {
// consider: 3 2 1 4
// x y
// consider: 2 1 3 4
// x y
if (nums.get(i) > nums.get(i + 1)) { // found
y = nums.get(i + 1); // update y
if (x == null) {
x = nums.get(i); // first (x = 3, y = 2)
} else {
break; // second (x = 3, y = 1)
}
}
}
return new int[] { x, y };
}
// Swap two elements
private void inorderSwap(TreeNode root, int count, int x, int y) {
if (root == null || count <= 0) {
return;
}
if (root.val == x || root.val == y) {
root.val = (root.val == x) ? y : x;
count -= 1;
}
inorderSwap(root.left, count, x, y);
inorderSwap(root.right, count, x, y);
}
Space: $O(N)$
Note: The following approach is based on swapping during inorder traversal.Iterativeandrecursiveapproaches here do less than one pass, but they both require up to $O(h)$ space to keep stack.Morrisapproach needs two passes, but it requires constant space.
- Construct inorder traversal of the tree. It should be an almost sorted list where
One-Pass (Iteration)
- To identify swapped nodes, track the last node
predin the inorder traversal and compare it with current node. If the current node is smaller thanpred, they are swapped nodes. Then we break the traversal after swapping.Time: $O(N)$1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30// One-Pass (Iteration)
public void recoverTree(TreeNode root) {
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode x = null, y = null, pred = null;
while (root != null || stack.size() > 0) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (pred != null && pred.val > root.val) {
y = root;
if (x == null) {
x = pred;
} else {
break;
}
}
pred = root;
root = root.right;
}
// swap
int temp = x.val;
x.val = y.val;
y.val = temp;
}
Space: $O(h)$
- To identify swapped nodes, track the last node
One-Pass (Recursion)
- Remember to do
pred = root!Time: $O(N)$1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public void recoverTree(TreeNode root) {
if (root == null) {
return;
}
x = null; y = null; pred = null;
inorderSwap(root);
// swap (assume x, y not null)
int temp = x.val;
x.val = y.val;
y.val = temp;
}
private void inorderSwap(TreeNode root) {
if (root == null) {
return;
}
inorderSwap(root.left);
if (pred != null && pred.val > root.val) {
y = root;
if (x == null) {
x = pred;
} else {
return;
}
}
pred = root;
inorderSwap(root.right);
}
Space: $O(h)$
- Remember to do
Morris Inorder Traversal
- Marked
- Time: $O(N)$
- Space: $O(1)$