Leetcode刷题99. 恢复二叉搜索树

给你二叉搜索树的根节点 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) 空间的解决方案吗?

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/recover-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

感谢windliang大神的详细解法,传送门详细通俗的思路分析,多解法

class Solution {
	TreeNode first = null, second = null;
    public void recoverTree(TreeNode root) {
		//如果两个节点相邻,只会产生一组逆序的数字,直接交换即可,例如[1 3 2 4 5]
		//如果两个节点不相邻,则会产生两种逆序的数字,我们需要将第一组的第一个数字与第二组的第二个数字进行交换,例如[1 5 3 4 2]
		//BST中序默认有序,遍历时如果前一节点值大于当前节点值则说明出现逆序对,分别用first和second保存。
		//如果找到第二组逆序的数字,将second更新成当前节点。最后first和second两个节点值交换即可。
//		recoverTreeI(root);
//		recoverTreeII(root);
		recoverTreeIII(root);
	}

	//方法三:morris遍历,时间复杂度O(N),空间复杂度O(1)
	private void recoverTreeIII(TreeNode root) {
		if (root == null) {
			return;
		}
		TreeNode cur = root;
		TreeNode fir = null, sec = null;
		TreeNode prev2 = null;
		while (cur != null) {
			if (cur.left != null) {
				TreeNode node = cur.left;
				while (node.right != null && node.right != cur) {
					node = node.right;
				}
				if (node.right == null) {
					node.right = cur;
					cur = cur.left;
					continue;
				} else {
					node.right = null;
				}
			}
			if (prev2 != null && prev2.val > cur.val) {
				if (fir == null) {
					fir = prev2;
				}
				sec = cur;
			}
			prev2 = cur;
			cur = cur.right;
		}

		if (fir != null && sec != null) {
			int temp = fir.val;
			fir.val = sec.val;
			sec.val = temp;
		}
	}

	//方法二:迭代,时间和空间复杂度O(N)
	private void recoverTreeII(TreeNode root) {
		if (root == null) {
			return;
		}
		Stack<TreeNode> stack = new Stack<>();
		TreeNode prev2 = null;
		while (!stack.isEmpty() || root != null) {
			while (root != null) {
				stack.push(root);
				root = root.left;
			}
			root = stack.pop();
			if (prev2 != null && prev2.val > root.val) {
				if (first == null) {
					first = prev2;
				}
				second = root;
			}
			prev2 = root;
			root = root.right;
		}
		if (first != null && second != null) {
			int temp = first.val;
			first.val = second.val;
			second.val = temp;
		}
	}

	//方法一:递归,时间和空间复杂度O(N)
	private void recoverTreeI(TreeNode root) {
		inorderTraversal(root);
		if (first != null && second != null) {
			int temp = first.val;
			first.val = second.val;
			second.val = temp;
		}
	}

	TreeNode prev = null;
	private void inorderTraversal(TreeNode root) {
		if (root == null) {
			return;
		}
		inorderTraversal(root.left);
		if (prev != null && prev.val > root.val) {
			//第一次遇到逆序对
			if (first == null) {
				first = prev;
				second = root;
			} else {
				//第二次遇到逆序对
				second = root;
			}
		}
		prev = root;
		inorderTraversal(root.right);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值