【LeetCode】每日一题 缺失的第一个正数

86 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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;
};

如果你对这道题目还有疑问的话,可以在评论区进行留言;

\