携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
41. 缺失的第一个正数
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
「示例1:」
输入:nums = [1,2,0]
输出:3
「示例2:」
输入:nums = [3,4,-1,1]
输出:2
「示例3:」
输入:nums = [7,8,9,11,12]
输出:1
「提示:」
1 <= nums.length <= 5 * 105
-231 <= nums[i] <= 231 - 1
解题思路
// 第一种
循环nums,当前元素在(0,nums.lenght]之间,并且nums[nums[i]-1] != nums[i],则交换位置,然后循环交换位置之后的数组,判断第一个缺失的正数
复杂度:时间复杂度O(n),空间复杂度O(1)
// 第二种
是最先容易想到的一种,即先把数组过滤成正整数,再进行升序排列,然后遍历后一个值减前一个值进行筛选。
这种解法问题在于排序多消耗了遍历次数。
这个在第一种解法基础上优化了一下,利用选择排序的原理(即每次遍历都会把最小值放到最左边),因此可以边遍历边对比值,从而减少遍历次数。
代码实现
// 第一种
var firstMissingPositive = function(nums) {
for(let i = 0; i < nums.length; i++){
//循环nums,当前元素在(0,nums.lenght]之间,并且nums[nums[i]-1] != nums[i],则交换位置
while(nums[i] > 0 && nums[i] <= nums.length && nums[nums[i]-1] != nums[i] ){
const temp = nums[nums[i]-1];
nums[nums[i]-1] = nums[i];
nums[i] = temp;
}
}
for(let i = 0; i < nums.length; i++){//循环交换位置之后的数组,判断第一个缺失的正数
if(nums[i] != i+1){
return i+1;
}
}
// [1,2,3]
return nums.length + 1;
};
// 第二种
<!-- 解法二代码 -->
var firstMissingPositive = function(nums) {
// 利用选择排序的原理,减少数组遍历次数
nums = nums.filter(item=>{ return item > 0;})
let min;
for(let i = 0;i<nums.length; i++){
min = nums[i];
for(let j = i+1; j<nums.length; j++){
if(min > nums[j]){
let temp = min;
min = nums[j];
nums[j] = temp;
}
}
// 当把后面的值都遍历完后,当前值和标记出来的值交换位置
nums[i] = min;
if(i>0){
if(nums[i] - nums[i-1]>1){
return nums[i-1] + 1;
}
}else{ // 只遍历出第一个最小值时
if(min !== 1){
return 1;
}
}
}
// 如果数组是连续的正整数,注意:此处不能用数组长度直接+1,因为会有相同元素的数组情况,如[1,1]
return nums.length ? nums.pop() +1 : 1;
};
如果你对这道题目还有疑问的话,可以在评论区进行留言;
\