题目描述
给你一个 严格升序排列 的正整数数组 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.length
的i
和j
满足arr[i] < arr[j]
思路讲解
这道题可以用枚举法,也可以用二分法。我们先来看用枚举法怎么做
枚举法
我们用一个current变量记录当前应该出现的数组。从 1 开始,每次循环都让该变量递增。用一个指针 ptr 指向数组中没有匹配的第一个元素,每轮循环中将该元素和current 进行比较,如果相等,则指针后移,否则指针留在原地不动,说明缺失正整数 current。我们用 missCount 变量记录缺失的正整数的个数,每次发现有正整数缺失的时候,该变量自增,并且记录这个缺失的正整数,直到我们找到第 k 个缺失的正整数。
var findKthPositive = function(arr, k) {
let missCount = 0, lastMiss = -1, current = 1, ptr = 0;
for (missCount = 0; missCount < k; ++current) {
if (current == arr[ptr]) {
ptr = (ptr + 1 < arr.length) ? ptr + 1 : ptr;
} else {
++missCount;
lastMiss = current;
}
}
return lastMiss;
};
二分法
二分法的原理就是如果数组是严格递增的,那么arr[i]应该等于i。那么arr[mid] -(1+mid)就是当前缺少的数字的数量,将这个数与k比较,就可以得到left和right。left等于right时,left+k就是第k个缺失的正整数。
/**
* @param {number[]} arr
* @param {number} k
* @return {number}
*/
var findKthPositive = function (arr, k) {
let left = 0, right = arr.length, mid
while (left < right) {
mid = (left + right) >> 1//右移运算符>>,运算结果正好能对应一个整数的二分之一值,这就正好能代替数学上的除2运算,但是比除2运算要快。
if (arr[mid] - 1 - mid < k) {
left = mid + 1
} else {
right = mid
}
}
return left + k
};
总结
最简单的方法就是使用数组的方法indexOf()或者find()方法。遍历1-arr.length+k。如果indexOf(i) == -1 说明这个数不在数组中,num++,如果num == k就返回此时的i。
/**
* @param {number[]} arr
* @param {number} k
* @return {number}
*/
var findKthPositive = function(arr, k) {
let num = 0
for (let i = 1; i <= arr.length + k; i++ ) {
if (arr.indexOf(i) < 0) {
num++
}
if (num == k) {
return i
}
}
};
本题之所以可以用二分法来算。主要就是数组的下标和数组的值具有某种关系。值-下标就是此时有几个缺失的正整数。所以就可以用二分法来确定第k个正整数的范围。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情