缺失的第一个正数

65 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

第 28 天

缺失的第一个正数

image.png

题目

给你一个未排序的整数数组 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

题解

两种解法:

是最先容易想到的一种,即先把数组过滤成正整数,再进行升序排列,然后遍历后一个值减前一个值进行筛选。 这种解法问题在于排序多消耗了遍历次数。 这个在第一种解法基础上优化了一下,利用选择排序的原理(即每次遍历都会把最小值放到最左边),因此可以边遍历边对比值,从而减少遍历次数。

<!-- 解法二代码 -->
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;
};

解法二:

var firstMissingPositive = function(nums) {
  for (const num of nums)
    if (typeof nums[+num - 1] !== 'undefined')
      nums[+num - 1] = '' + nums[+num - 1]
  for (let i = 0; i < nums.length; i++)
    if (typeof nums[i] === 'number')
      return i + 1
  return nums.length + 1
};