leetcode1060. 有序数组中的缺失元素

给出一个有序数组 A,数组中的每个数字都是 独一无二的,找出从数组最左边开始的第 K 个缺失数字。

示例 1:

输入:A = [4,7,9,10], K = 1
输出:5
解释:
第一个缺失数字为 5 。

示例 2:

输入:A = [4,7,9,10], K = 3
输出:8
解释: 
缺失数字有 [5,6,8,...],因此第三个缺失数字为 8 。

示例 3:

输入:A = [1,2,4], K = 3
输出:6
解释:
缺失数字有 [3,5,6,7,...],因此第三个缺失数字为 6 。

提示:

  1. 1 <= A.length <= 50000
  2. 1 <= A[i] <= 1e7
  3. 1 <= K <=1e8

 题解与思路

思路

由于数组是有序的,我们可以通过比较数组中的元素和它们的索引来确定缺失了多少个数字。具体来说,对于数组中的每个元素A[i]A[i],在位置ii上,如果没有缺失任何数字,那么A[i] = i + 1 + A[0] - 1 A[i]=i+1+A[0]−1。这里,A[0] - 1A[0]−1是初始偏移量,因为数组不一定从1开始。因此,对于任何位置ii,到这个位置为止缺失的数字数量应该是A[i] - i - 1 - (A[0] - 1)A[i]−i−1−(A[0]−1)。

我们可以利用这个关系进行二分查找:

  1. 计算中间位置midmid的缺失数字数量。
  2. 如果缺失数量小于KK,说明第KK个缺失的数字在右侧,我们向右二分。
  3. 如果缺失数量大于或等于KK,说明第KK个缺失的数字在左侧或就是当前位置,我们向左二分。
  4. 当我们缩小到某个点时,根据KK和左侧缺失数量的差值,我们可以直接计算出确切的缺失数字。
/*
 * 题解
 * 由于数组是有序的,我们可以通过比较数组中的元素和它们的索引来确定缺失了多少个数字。具体来说,对于数组中的每个元素A[i],在位置i上,如果没有缺失任何数字,那么A[i]=i+1+A[0]-1。这里,A[0] - 1是初始偏移量,因为数组不一定从1开始。因此,对于任何位置i,到这个位置为止缺失的数字数量应该是A[i] - i - 1 - (A[0] - 1)。
 *
 * 我们可以利用这个关系进行二分查找:
 *
 * 计算中间位置midmid的缺失数字数量。
 * 如果缺失数量小于KK,说明第KK个缺失的数字在右侧,我们向右二分。
 * 如果缺失数量大于或等于KK,说明第KK个缺失的数字在左侧或就是当前位置,我们向左二分。
 * 当我们缩小到某个点时,根据KK和左侧缺失数量的差值,我们可以直接计算出确切的缺失数字。
 */
public class Solution{
    public static int missingElement(int[] nums, int k) {
        int n = nums.length;
        int left = 0, right = n - 1;

        // 如果k大于数组末尾缺失的数量,则直接计算并返回
        //具体逻辑 我以A[0]是参照物 然后我去算 如果没有任何缺数的情况 那么我这个末尾应该是多少
        // 然后用实际的去减去应该的即是我们这边一共插了多少个
        int missingNums = nums[n - 1] - nums[0] + 1 - n;

        if (k > missingNums) {
            return nums[n - 1] + k - missingNums;
        }

        // 二分查找
        while (left < right) {
            int mid = left + (right - left) / 2;
            missingNums = nums[mid] - nums[0] - mid;

            if (missingNums < k) {
                // 缺失的数字在右侧
                left = mid + 1;
            } else {
                // 缺失的数字在左侧或当前位置
                right = mid;
            }
        }

        // 计算第K个缺失数字
        return nums[left - 1] + k - (nums[left - 1] - nums[0] - (left - 1));
    }

    public static void main(String[] args) {
        int [] arr=new int[10];
        arr= new int[]{1, 3, 4, 7, 10};
        System.out.println(missingElement(arr, 400));
    }



}
/*
 * 我们通过二分查找确定第KK个缺失数字的大致位置。
 * 二分查找的终止条件是left < right,最终left和right会相遇,在这个点左侧的缺失数量加上KK可以直接计算出第KK个缺失的数字。
 * 注意,由于我们的计算方法,需要在最后的计算中考虑到左侧边界,即nums[left - 1],这是因为我们的left和right最终会停在缺失数字应当插入的位置。
 */
  • 我们通过二分查找确定第KK个缺失数字的大致位置。
  • 二分查找的终止条件是left < right,最终leftright会相遇,在这个点左侧的缺失数量加上KK可以直接计算出第KK个缺失的数字。
  • 注意,由于我们的计算方法,需要在最后的计算中考虑到左侧边界,即nums[left - 1],这是因为我们的leftright最终会停在缺失数字应当插入的位置。
  • 这个题目感觉还行 一起加油啦 大家

 

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一心向上的小奥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值