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. 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)$
 
