Restore a Search Tree After Two Values Were Swapped
Solve this ProblemYou are given the root of a binary tree that was a valid binary search tree with distinct values, until the values of exactly two of its nodes were swapped with each other. Restore the tree by putting the two values back where they belong, without changing the shape of the tree, and return its root.
The inorder sequence of a search tree is sorted, so a swap leaves the sequence sorted except for two exchanged values. Comparing with a sorted copy finds them; a single inorder walk that watches for a value smaller than its predecessor finds them without any extra storage.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
2 ≤ number of nodes ≤ 100; all node values are distinct, 0 ≤ node.val ≤ 1000 - ◆
The tree WAS a binary search tree, but the values of exactly two of its nodes have been swapped with each other; the shape is unchanged. It is given by its root node - ◆
Restore the search-tree property by putting the two values back where they belong — change only the values of those two nodes, not the shape - ◆
Return the root of the repaired tree (checked as a level-order list)
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Compare the Inorder Values With Their Sorted Copy
BruteThe inorder sequence of a search tree is sorted, so the damaged tree's inorder sequence is a sorted list with exactly two values exchanged. Collect the nodes in inorder, sort a copy of their values, and compare the two lists position by position: exactly two positions differ. The nodes at those two positions are the swapped ones; exchange their values. The sort costs O(n log n) and both lists take O(n) space.
O(n log n)O(n)1class Solution {
2 public TreeNode fixSwappedNodes(TreeNode root) {
3 List<TreeNode> nodes = new ArrayList<>();
4 collect(root, nodes);
5 List<Integer> sorted = new ArrayList<>();
6 for (TreeNode n : nodes) sorted.add(n.val);
7 Collections.sort(sorted);
8 TreeNode first = null, second = null;
9 for (int i = 0; i < nodes.size(); i++) {
10 if (nodes.get(i).val != sorted.get(i)) {
11 if (first == null) first = nodes.get(i);
12 else second = nodes.get(i);
13 }
14 }
15 if (first != null && second != null) {
16 int tmp = first.val;
17 first.val = second.val;
18 second.val = tmp;
19 }
20 return root;
21 }
22
23 private void collect(TreeNode node, List<TreeNode> nodes) {
24 if (node == null) return;
25 collect(node.left, nodes);
26 nodes.add(node);
27 collect(node.right, nodes);
28 }
29}Optimal — One Inorder Walk That Spots the Out-of-Order Pairs
OptimalWalk the tree in inorder while remembering the previously visited node (prev). Whenever prev.val > node.val, the sequence goes DOWN — an inversion. Swapping two values creates either two inversions (non-neighbours in sorted order) or one (neighbours). At the first inversion, the bigger value prev is the first culprit; keep updating the second culprit to the current node at every inversion, so after the walk second is the smaller value that was pushed too far right (from the first inversion if there is only one). Swap the values of first and second. One pass and O(h) recursion space; no sorting and no list.
O(n)O(h)1class Solution {
2 private TreeNode prev, first, second;
3
4 public TreeNode fixSwappedNodes(TreeNode root) {
5 prev = null;
6 first = null;
7 second = null;
8 walk(root);
9 if (first != null && second != null) {
10 int tmp = first.val;
11 first.val = second.val;
12 second.val = tmp;
13 }
14 return root;
15 }
16
17 private void walk(TreeNode node) {
18 if (node == null) return;
19 walk(node.left);
20 if (prev != null && prev.val > node.val) {
21 if (first == null) first = prev;
22 second = node;
23 }
24 prev = node;
25 walk(node.right);
26 }
27}