「前端刷题」99. 恢复二叉搜索树

307 阅读2分钟

「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。

题目

链接:leetcode-cn.com/problems/re…

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

示例 1:

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

示例 2:

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

提示:

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

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

思路

思路:中序遍历,递归

对于一颗搜索二叉树,按照中序遍历来遍历它,会得到一个升序序列。

我们只需要中序遍历题目给定的二叉树,就会得到一个被调换两个元素的升序序列。找到这两个被调换的元素,然后将它们的 val 属性交换就行了。

我们可以用一个 pre 变量来存储前一个节点,然后在中序遍历的过程当中,将 pre 节点的值与当前遍历节点的值进行比较

这里考虑两种情况:

  1. 相邻的元素调换;
  2. 不相邻的元素调换。
  • 对于相邻的元素被调换,在中序遍历的过程中,只会出现一次 pre 节点的值大于当前遍历节点的值。

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

  • 而对于不相邻的元素被调换,在中序遍历的过程中,则会出现两次 pre节点的值大于当前遍历节点的值。

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

我们可以定义两个变量 needChangeOne, needChangeTwo 表示被调换的两个节点

在第一次遇到 pre 节点的值大于当前遍历节点的值时,分别将 pre 节点和当前节点赋值给 needChangeOne, needChangeTwo

  • 如果后面没有再出现 pre 节点的值大于当前节点的值,则它俩已经找到了;

  • 如果后面又出现了pre 节点的值大于当前节点的值,则在用当前节点去覆盖变量 needChangeTwo

注意:对于两次出现 pre节点的值大于当前遍历节点的值的情况,第一次是将 pre 赋值给 needChangeOne,第二次是将当前节点赋值给 needChangeTwo

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {void} Do not return anything, modify root in-place instead.
 */
var recoverTree = function (root) {
	let pre = null;
	let needChangeOne = null, needChangeTwo = null;
	
	const dfs = (current) => {
		if(!current) return;
		dfs(current.left);
		if(pre !== null && pre.val > current.val) {
			if(!needChangeOne) {
				needChangeOne = pre;
				needChangeTwo = current;
			}
			else {
				needChangeTwo = current;
			}
		}
		pre = current;
		dfs(current.right);
	}

	dfs(root);
	[needChangeOne.val, needChangeTwo.val] = [needChangeTwo.val, needChangeOne.val];
};