第k个缺失的正整数

199 阅读2分钟

1、题目描述

给你一个 严格升序排列 的正整数数组 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 。

2、思路

方法一:枚举

  • 首先用一个变量current表示当前应该出现的数,从1开始,每次循环都让current递增

  • 用指针ptr指向数组中没有匹配的第一个元素

  • 每轮循环中将该元素和current进行比较,如果相等,则将指针后移,否则指针原地不动,代表current元素缺失。

  • 利用missCount记录缺失的正整数个数,利用lastMiss记录最后一个缺失的正整数

  • 需要注意的是,数组有效范围内缺失元素个数小于k的时候,需要继续往后遍历 方法二:二分查找

  • 对于数组每个元素ai,;我们都可以知道到第i个元素为止缺失的元素数量为ai-i-1

  • 观察每个元素对应的缺失个数,发现是一个非严格递增序列,我们可以在该序列中,通过二分查找,找到k所对应的位置。

  • 根据这种分析,我们就可以在这个缺失数量的序列上进行二分查找,确定一个区间[i,j],满足lack[i] < k <= lack[j],则第k个缺失的数为k - (arr[i] - i - 1) + arr[i],arr[i] - i - 1表示arr[i]位置缺少的元素个数,k - 缺失个数表示从arr[i]开始还缺少几个元素,再加上arr[i],就是第k个缺失的元素。

  • 在这里我们需要注意两个边界值的处理,一个是当a0大于k的时候,提前判断,直接返回。另一个是当最后一个元素对应的缺失元素个数小于k的时候,可以在a序列的后面加入一个非常大的虚拟值,这样就能保证找到一个大于等于k的缺失元素个数

3、代码实现

方法一:

class Solution {
    public int findKthPositive(int[] arr, int k) {
        if (arr[0] > k) {
            return k;
        }

        int l = 0, r = arr.length;
        while (l < r) {
            int mid = (l + r) >> 1;
            int x = mid < arr.length ? arr[mid] : Integer.MAX_VALUE;
            if (x - mid - 1 >= k) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }

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

方法二:

class Solution {
    public int findKthPositive(int[] arr, int k) {
        if(arr[0] > k){
            return k;
        }
        int left = 0;
        int right = arr.length;
        while(left < right){
            int mid = left + (right -left) / 2;
            int x = mid < arr.length ? arr[mid] : Integer.MAX_VALUE;
            if(x - mid - 1 >= k){
                right = mid;
            }
            else{
                left = mid + 1;
            }
        }
        return k - (arr[right-1] - (right-1) - 1) + arr[right-1];
    }
}