【LeetCode】99. 恢复二叉搜索树

123 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

题目

给你二叉搜索树的根节点 root ,该树中的恰好两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。

示例 1

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 13 使二叉搜索树有效。

示例 2

输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 23 使二叉搜索树有效。

提示

  • 树上节点的数目在范围 [2, 1000] 内
  • -2^31 <= Node.val <= 2^31 - 1

进阶:使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用 O(1) 空间的解决方案吗?

题解

思路

首先确定遍历顺序:

二叉树的遍历有前、中、后三种顺序,对于二叉搜索树 在中序遍历的情况下可以按照节点值从小到大遍历节点,因此这里确定使用中序遍历,拿出中序遍历的模板。

class Solution {
public:
    void backtracking(TreeNode* node) {
        if (node == NULL) return;
        backtracking(node->left);
        { do whatever you want to do }
        backtracking(node->right);
    }
    void inorderTraversal(TreeNode* root) {
        backtracking(root);
    }
};

接下来的任务就是完成{do whatever you want to do}模块,由于节点被错误换位之后(node1, node2)存在以下特性:

  • node1的值会比遍历到的后面一个节点值大
  • node2的值会比遍历到的前面一个节点值小

例:[1, 2, 3, 4, 5] -> [1, 4, 3, 2, 5]

这里4比后续节点3大, 而2比前序节点小,因此需要交换4与2

注意:这里节点3的值也比前序节点4小,因此node2的迭代逻辑就在这里诞生

在node1已经确定的情况下,若出现当前节点比前序节点大的情况,更新node2,最后在遍历结束后用swap函数完成交换。

代码

class Solution {
public:
    TreeNode* pre;
    TreeNode* node1;
    TreeNode* node2;
    void backtracking(TreeNode* node) {
        if (node == NULL) return;
        backtracking(node->left);
        // 若不是第一个节点 node1之前没有出现 但是现在出现了 记录下来(node1 被记录下后就不会变)
        if (pre != NULL && node1 == NULL && node->val < pre->val) node1 = pre;
        // 若不是第一个节点 node1 出现了 且满足node2的条件 记录下来
        if (pre != NULL && node1 != NULL && node->val < pre->val) node2 = node;
        pre = node;
        backtracking(node->right);
    }
    void recoverTree(TreeNode* root) {
        backtracking(root);
        swap(node1->val, node2->val);
    }
};

结语

业精于勤,荒于嬉;行成于思,毁于随。