前端算法第一五零期-第 k 个缺失的正整数

88 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。

请你找到这个数组里第 k 个缺失的正整数。

示例 1:

输入:arr = [2,3,4,7,11], k = 5
输出:9
解释:缺失的正整数包括 [1,5,6,8,9,10,12,13,...] 。第 5 个缺失的正整数为 9 。

示例 2:

输入:arr = [1,2,3,4], k = 2
输出:6
解释:缺失的正整数包括 [5,6,7,...] 。第 2 个缺失的正整数为 6 。

提示:

  • 1 <= arr.length <= 1000
  • 1 <= arr[i] <= 1000
  • 1 <= k <= 1000
  • 对于所有 1 <= i < j <= arr.lengthij 满足 arr[i] < arr[j]

二分查找

对于每个元素 aia_i,我们都可以唯一确定到第 i 个元素为止缺失的元素数量为 aii1a_i - i - 1 ,例如:

图片.png

我们发现 pip_i 是随 i 非严格递增的,于是可以使用二分查找解决这个问题。我们只要找到一个 i 使得 pi1<kpip_{i - 1} < k \leq p_{i},就可以确定缺失的第 k 个数为 kpi1+ai1k - p_{i - 1} + a_{i - 1}。也就是说,我们要找到第一个大于等于 k 的 pip_i

在实现的时候,我们要注意两个边界的处理:

  • a0>ka_0 > k 时,最终 i=0i = 0,找不到 i1i - 1,所以提前判断是否 a0>ka_0 > k,如果是,则直接返回 kk
  • 当最后一个元素对应的缺失个数 pn1<kp_{n - 1} < k 时,我们并不能找到第一个大于等于 kkpip_i,为了解决这个问题,可以在 aa 序列的最后加入一个虚拟的值,这个值的大小为一个不会出现的非常大的数,这样就可以保证一定能找到一个大于等于 kkpip_i
var findKthPositive = function(arr, k) {
    if (arr[0] > k) {
        return k;
    }

    let l = 0, r = arr.length;
    while (l < r) {
        const mid = Math.floor((l + r) / 2);
        let x = mid < arr.length ? arr[mid] : 2000000;
        if (x - mid - 1 >= k) {
            r = mid;
        } else {
            l = mid + 1;
        }
    }

    return k - (arr[l - 1] - (l - 1) - 1) + arr[l - 1];
};

复杂度分析

  • 时间复杂度:O(logn)O(\log n) ,其中 nn 是数组 arr\textit{arr} 的长度。即二分查找的时间复杂度。
  • 空间复杂度:O(1)O(1)

图片.png