Recover Binary Search Tree - Complete Solution Guide
Recover Binary Search Tree is LeetCode problem 99, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
You are given the root of a binary search tree (BST), where the values of exactly two nodes of the tree were swapped by mistake. Recover the tree without changing its structure . Example 1: Input: root = [1,3,null,null,2] Output: [3,1,null,null,2] Explanation: 3 cannot be a left child of 1 because 3 > 1. Swapping 1 and 3 makes the BST valid. Example 2: Input: root = [3,1,4,null,null,2] Output: [2,1,4,null,null,3] Explanation: 2 cannot be in the right subtree of 3 because 2 < 3. Swapping 2 and 3
Detailed Explanation
The problem asks us to recover a Binary Search Tree (BST) where exactly two nodes have been swapped. The goal is to identify these two swapped nodes and restore the BST property by swapping their values back. The structure of the tree must remain unchanged. Input is the root of the corrupted BST, and the output is the modified (recovered) BST. The constraints specify the size of the tree (2 to 1000 nodes) and the range of node values (-2^31 to 2^31 - 1).
Solution Approach
The solution utilizes Morris traversal (threaded binary tree traversal) to perform an in-order traversal of the BST in O(1) space. During the traversal, it keeps track of the previous node visited and checks if the current node's value is less than the previous node's value. If this condition is met, it indicates a violation of the BST property, meaning that we've encountered a node that's out of order due to the swap. The first time this happens, we mark the 'previous node' as the 'first_node'. Subsequent violations indicate the second misplaced node. The last violation is identified as the 'second_node'. After the entire tree is traversed, the values of 'first_node' and 'second_node' are swapped to recover the BST.
Step-by-Step Algorithm
- Step 1: Initialize `first_node`, `second_node` to None, and `prev_node` to a TreeNode with value negative infinity to handle the first comparison correctly.
- Step 2: Start Morris traversal. While `current` is not None, do:
- Step 3: If `current` does not have a left child:
- Step 4: Check if `prev_node.val > current.val`. If true, then:
- Step 5: If `first_node` is None, assign `prev_node` to `first_node`.
- Step 6: Assign `current` to `second_node`.
- Step 7: Update `prev_node` to `current`.
- Step 8: Move to the right child: `current = current.right`.
- Step 9: Else (if `current` has a left child):
- Step 10: Find the in-order predecessor of `current`.
- Step 11: If the predecessor's right child is None, then:
- Step 12: Set predecessor's right child to `current` (create the thread).
- Step 13: Move to the left child: `current = current.left`.
- Step 14: Else (predecessor's right child is `current`):
- Step 15: Remove the thread: set predecessor's right child to None.
- Step 16: Check if `prev_node.val > current.val`. If true, then:
- Step 17: If `first_node` is None, assign `prev_node` to `first_node`.
- Step 18: Assign `current` to `second_node`.
- Step 19: Update `prev_node` to `current`.
- Step 20: Move to the right child: `current = current.right`.
- Step 21: After the traversal, swap the values of `first_node` and `second_node` if they exist.
Key Insights
- Insight 1: In-order traversal of a BST yields a sorted sequence. Deviations from this sorted order indicate the swapped nodes.
- Insight 2: Morris traversal provides an in-order traversal in O(1) space, fulfilling the follow-up requirement.
- Insight 3: We need to identify the first node that violates the sorted order and the second node that contributes to the violation. These are the nodes to be swapped.
Complexity Analysis
Time Complexity: O(n)
Space Complexity: O(1)
Topics
This problem involves: Tree, Depth-First Search, Binary Search Tree, Binary Tree.
Companies
Asked at: Amazon, Apple, Bloomberg, Microsoft, TikTok, Yahoo.