Description Link to heading

99. Recover Binary Search Tree (Medium)

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 makes the BST
valid.

Constraints:

  • The number of nodes in the tree is in the range [2, 1000].
  • -2³¹ <= Node.val <= 2³¹ - 1

Follow up: A solution using O(n) space is pretty straight-forward. Could you devise a constant O(1) space solution?

Solution Link to heading

In this context, we shall consider a solution with a time complexity of $O(1)$. Initially, it is worth noting that when conducting an in-order traversal of a binary search tree, the node values strictly follow an ascending order. Consequently, we may exploit this insight to identify the two nodes that have been swapped.

Let us contemplate an ascending sequence and the exchange of any two elements within it. If these two elements happen to be adjacent, then during our traversal, a situation will arise wherein $a_{i} < a_{i - 1}$. On the other hand, if these two elements are not adjacent, we will encounter $a_{i} < a_{i - 1}$ twice. We shall store all such pairs of elements where $a_{i} < a_{i - 1}$ in an array called vec. Therefore, it follows that vec.size() == 2 || vec.size() == 4, and to rectify the situation, we need only swap the values of the first and last elements in the array.

As we traverse in an in-order manner, we can employ the prev variable to represent the pointer to the previous node in the traversal. By comparing the values of root->val and prev->val, we can ascertain whether the sequence adheres strictly to the increasing order. If it does not, we shall consecutively push_back both root and prev into the vec array, and finally, perform a swap between vec[0]->val and vec.back()->val.

Below is a template for an in-order traversal incorporating the prev variable:

void midtra(TreeNode *root, TreeNode **prev) {
    if (root == nullptr) {
        return;
    }
    midtra(root->left, prev);
    *prev = root;
    midtra(root->right, prev);
}

Code Link to heading

class Solution {
  public:
    void midtra(TreeNode *root, TreeNode **prev, vector<TreeNode *> &wrong) {
        if (root == nullptr) {
            return;
        }
        midtra(root->left, prev, wrong);
        if (*prev != nullptr) {
            if (root->val < (*prev)->val) {
                wrong.push_back(*prev);
                wrong.push_back(root);
            }
        }
        *prev = root;
        midtra(root->right, prev, wrong);
    }
    void recoverTree(TreeNode *root) {
        // 中序遍历
        vector<TreeNode *> wrong;
        TreeNode *node = nullptr;
        midtra(root, &node, wrong);
        swap(wrong[0]->val, wrong.back()->val);
    }
};