题目:恢复二叉搜索树 hard
二叉搜索树中的两个节点被错误地交换。
请在不改变其结构的情况下,恢复这棵树。
示例 1:
输入: [1,3,null,null,2]
1
/
3
\
2
输出: [3,1,null,null,2]
3
/
1
\
2
示例 2:
输入: [3,1,4,null,null,2]
3
/ \
1 4
/
2
输出: [2,1,4,null,null,3]
2
/ \
1 4
/
3
进阶:
使用 O(n) 空间复杂度的解法很容易实现。
你能想出一个只使用常数空间的解决方案吗?
package leetCode.DFS;
import java.util.ArrayDeque;
import java.util.Stack;
public class lc_rt_99_recoverTree{
/*
思路:
步骤:
1)先找到两个交换的节点-逆序对
二叉搜索树的中序遍历结果可以等效于一个升序数组
因此先用数组举例,如果原始的二叉搜索树为
1, 2, 3, 4, 5
如果将其中2,4两个元素进行交换,变成
1, 4, 3, 2, 5
那么我们可以使用双指针的方法,检查这个数组里的逆序对,将逆序对找出来就可以解决问题
观察数组
第一对逆序对4, 3,是索引小的那个是被交换元素
第二对逆序对3, 2,是索引大的那个是被交换元素
所以我们在遇到逆序对的时候,如果是第一次遇见,则存储索引小的那个,如果不是,则存储索引大的那个
if(pre != NULL && root.val < pre.val){
if(s1 == NULL) s1 = pre; // 索引小的已经找到,就不再改变
s2 = cur;
}
为什么这里s2用的不是else?
因为存在两个相邻元素交换的情况,所以我们在第一次遇见的把索引大的那个也存下来
如果后面没有逆序对了,那就是这一对
如果后面还有逆序对,会覆盖s2(因为有if判断,所以s1不会被覆盖)
2)找到交换的两个节点后就直接交换结点的值
可以采用:
1.递归中序遍历
2.迭代(非递归)中序遍历
3.mirror中序遍历(更好的空间复杂度,但暂时没去研究):见以下链接
https://leetcode-cn.com/problems/recover-binary-search-tree/solution/zhong-xu-bian-li-shuang-zhi-zhen-zhao-ni-xu-dui-mo/
*/
//方法1:递归中序遍历
TreeNode pre = null;//存储前一个结点
TreeNode x = null;//存储需要交换的一个节点
TreeNode y = null;//存储另一个节点
public void recoverTree(TreeNode root) {
midOrder(root);
swap(x, y);
}
// 方法2:迭代中序遍历,即非递归方式的中序遍历
public void recoverTree2(TreeNode root) {
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
while (root != null || !stack.isEmpty()) {
if (root != null) {
//注意这里使用的是add,不是push,ArrayDeque实际是个队列不是stack
stack.add(root);
root = root.left;
} else {
TreeNode node = stack.removeLast();
if (pre != null && node.val < pre.val) {
y = node;
if (x == null)
x = pre;
else
break;
}
pre = node;
root = node.right;
}
}
swap(x, y);
}
/*
中序遍历,找出需要交换的x和y节点
*/
public void midOrder(TreeNode root) {
if (root == null)
return;
midOrder(root.left);
if (pre != null && root.val < pre.val) {
y = root;
if (x == null)//第一次如果已经找到x,第二次判断时x非空,不会被重置
x = pre;
else
return;//第二次x!=null,y重新赋值后,两个结点都已经找到,不用继续遍历,结束
}
pre = root;
midOrder(root.right);
}
/*
交换两节点的值
*/
public void swap(TreeNode x, TreeNode y) {
int t = x.val;
x.val = y.val;
y.val = t;
}
//内部类
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
}