leetcode 99恢复二叉搜索树

leetcode 99 恢复二叉搜索树

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

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

第一种解法

题目要求的是二叉搜索树,二叉搜索树有一个特点,那就是有序,所以我们可以得知在中序遍历二叉搜索树得到的序列是递增的。
现在题目给出有两个节点被错误的交换了,那在中序遍历的序列中就可以体现出来了,那就是里面有数据是非递增的,也就是存在nums[i] > nums[i+1],如果是相邻的两个节点被交换了,那就只有一个位置进行了交换,如果不是那就存在两个位置的进行了交换。即nums[i] > nums[i+1]或nums[i] > nums[i+1] 和 nums[j] > nums[j+1]。
由此可以确定解题思路:

  • 通过中序遍历得到一组序列
  • 在这个序列中找到哪两个节点进行了交换
  • 将两个节点的数据交换回来
代码如下:
public void recoverTree(TreeNode root) {
	List<Integer> nums = new ArrayList<Integer>();
    // 1、先遍历树,通过中序遍历,二叉搜索树在中序遍历的情况下为递增序列
    inorder(root, nums);
    // 2、查看树的哪连个节点交换了位置
    int[] swapped = findTwoSwapped(nums);
    // 3、将两个节点的数据交换回来
    recover(root, 2, swapped[0], swapped[1]);
}
/**
 * 中序遍历
 *
 * @param root
 * @param nums
 */
public void inorder(TreeNode root, List<Integer> nums) {
    if (root == null) {
        return;
    }
    inorder(root.left, nums);
    nums.add(root.val);
    inorder(root.right, nums);
}

/**
 * 找到交换了数据的位置
 *
 * @param nums
 * @return
 */
public int[] findTwoSwapped(List<Integer> nums) {
    int x = -1, y = -1;
    for (int i = 0; i < nums.size() - 1; i++) {
        if (nums.get(i + 1) < nums.get(i)) {// 如果后面的数小于前面的数,说明这里被交换过
            // 不满足位置交换的点有一个或两个
            // 如果有一个,那就是i和i+1是交换点
            // 如果有两个,那就是 i   和  j+1
            // 使用x表示下标为i的值,使用y表示下标为i+1的值
            y = nums.get(i + 1);
            if (x == -1) {
                x = nums.get(i);
            } else {
                break;
            }
        }
    }
    return new int[]{x, y};
}

/**
 * 还原二叉搜索树
 * @param root
 * @param count 交换的次数
 * @param x 交换的节点1
 * @param y 交换的节点2
 */
public void recover(TreeNode root,int count,int x,int y){
    if (root != null){
        if (root.val == x || root.val == y){
            root.val = root.val == x ? y : x;// 如果这个节点的值为x,那么原数据值为y,反之亦然
            if (--count == 0){
                return;
            }
        }
        recover(root.left,count,x,y);
        recover(root.right, count, x, y);
    }
}

在这里插入图片描述
时间复杂度为:O(N),N为二叉树的节点
空间复杂度为:O(N)

第二种解法:

第一种方法使用了额外的数组来存储中序遍历得到的序列,所以空间复杂度为O(N),可以不需要额外的空间进行存储序列,也能找到两个交换的节点,那就是在中序遍历的时候进行判断,判断后面的节点是否小于当前节点。
使用迭代进行中序遍历:

代码如下:
public void recoverTree(TreeNode root) {
	Stack<TreeNode> stack = new Stack<>();
    TreeNode x = null;
    TreeNode y = null;
    TreeNode pre = null;
    while (!stack.isEmpty() || root != null){
        while (root != null){
            stack.push(root);
            root = root.left;
        }
        root = stack.pop();
        if (pre != null && pre.val > root.val){
            y = root;
            if (x == null){
                x = pre;
            }else {
                break;
            }
        }
        pre = root;
        root = root.right;
    }
    swap(x,y);
}
/**
 * 交换函数
 * @param x
 * @param y
 */
public void swap(TreeNode x,TreeNode y){
    int temp = x.val;
    x.val = y.val;
    y.val = temp;
}

刷了一些leetcode,然后来写一些博客,加深自己解题的思路。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值