题目所属分类
传统的中序遍历 递归 和 必要背过的(Morris-traversal) O(n)算法
给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树 。
代码案例:输入:root = [1,3,null,null,2] 输出:[3,1,null,null,2] 解释:3 不能是 1 的左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。
题解
常用解法
时间复杂度 O(n) 空间复杂度 O(n)
class Solution {
List<TreeNode> list = new ArrayList<>();
public void dfs(TreeNode root){
if(root != null){
dfs(root.left);
list.add(root);
dfs(root.right);
}
}
public void recoverTree(TreeNode root) {
dfs(root);
TreeNode a = null;
TreeNode b = null;
for(int i = 0 ; i < list.size()-1 ; i++){
if(list.get(i).val > list.get(i+1).val){
b = list.get(i+1);
if(a == null){
a = list.get(i);
}
}
}
int t = a.val;
a.val = b.val;
b.val = t ;
}
}
空间复杂度为常数的解法
核心就是 当前左子树无右儿子的点指向root点 这里的y总的题解 从根节点开始遍历,直至当前节点为空为止:
如果当前节点没有左儿子,则打印当前节点的值,然后进入右子树; 如果当前节点有左儿子,则找当前节点的前驱。 (1) 如果前驱节点的右儿子为空,说明左子树没遍历过,则进入左子树遍历,并将前驱节点的右儿子置成当前节点,方便回溯; (2) 如果前驱节点的右儿子为当前节点,说明左子树已被遍历过,则将前驱节点的右儿子恢复为空,然后打印当前节点的值,然后进入右子树继续遍历; 中序遍历的结果就是二叉树搜索树所表示的有序数列。有序数列从小到大排序,但有两个数被交换了位置。共有两种情况:
交换的是相邻两个数,例如 1 3 2 4 5 6,则第一个逆序对,就是被交换的两个数,这里是3和2; 交换的是不相邻的数,例如 1 5 3 4 2 6,则第一个逆序对的第一个数,和第二个逆序对的第二个数,就是被交换的两个数,这里是5和2; 找到被交换的数后,我们将它们换回来即可。
class Solution {
public void recoverTree(TreeNode root) {
TreeNode first = null ;
TreeNode second = null ;
TreeNode p = null ;
while(root != null){
if(root.left == null){
if(p != null && p.val > root.val){
if(first == null){
first = p ; second = root ;
}else{
second = root;
}
}
p = root;
root = root.right;
}else{
TreeNode q = root.left;
while(q.right != null && q.right != root )q = q.right;
if (q.right == null){
q.right = root ;
root = root.left;
}else{
q.right = null;
if(p != null && p.val > root.val){
if(first == null){
first = p ; second = root ;
}else{
second = root;
}
}
p = root ;
root = root.right;
}
}
}
int t = first.val;
first.val = second.val;
second.val = t ;
}
}
|