给你二叉搜索树的根节点 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);
}
}