LeetCode:41. 缺失的第一个正数

题目描述

给定一个未排序的整数数组,找出其中没有出现的最小的正整数。

示例 1:

输入: [1,2,0]
输出: 3
示例 2:

输入: [3,4,-1,1]
输出: 2
示例 3:

输入: [7,8,9,11,12]
输出: 1
说明:

你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。

题目链接https://leetcode-cn.com/problems/first-missing-positive/

解题思路

普通情况:

1.先过滤掉非正整数部分

2.对过滤后的数组进行从小到大排序

3.通过判断相邻元素之间的差值是否大于 1 来判断未出现的最小正整数

题目答案

var firstMissingPositive = function(arr) {
  // 过滤掉非正整数
  arr = arr.filter(item => item > 0)
  // 开始排序判断
  if (arr.length > 0) {
    // 升序排序
    arr.sort((a, b) => a - b)
    // 第一个元素不是 1 的情况
    if (arr[0] !== 1) {
      return 1
    } else {
      // 开始找未出现的最小正整数
      for (let i = 0, len = arr.length - 1; i < len; i++) {
        if (arr[i + 1] - arr[i] > 1) {
          return arr[i] + 1
        }
      }
      // 如果数组都是连续的,如 [1, 2, 3],则前面循环不会返回值,那么返回最后一个元素并加一
      return arr.pop() + 1
    }
  } else {
    return 1
  }
};

测试结果

我们发现,性能似乎并不好,还有优化空间。

优化方案:我们可以利用选择排序,在排序过程中就找出未出现的最小正整数,而不用先排序完后再查找。但我们发现,题目要求时间复杂度应为O(n),而选择排序的平均时间复杂度为O(n^2),所以不合题意。

说到这儿,我们应该思考,上面代码中用到的 sort 排序是否符合时间复杂度的要求呢?这就需要我们了解其原理了

sort 原理:当数组长度小于等于10的时候,采用插入排序,大于10的时候,采用快速排序。对于长度大于1000的数组,采用的是快排与插入排序混合的方式进行排序的,因为,当数据量很小的时候,插入排序效率优于快排。快排的平均时间复杂度是nlogn,插入排序的平均时间复杂度为O(n^2),所以我们的代码不符合题意。

另一种解题思路

遍历一次数组,把大于等于1的且小于数组长度大小的值放到原数组对应位置(符合 index+1 = arr[index] 的条件),然后再遍历一次数组查当前下标是否和值对应,如果不对应那这个下标就是答案,否则遍历完都没出现那么答案就是数组长度加1。

var firstMissingPositive = function(arr) {
  let i = 0
  let j, tmp
  while (i < arr.length) {
    j = arr[i] - 1
    if (j >= 0 && j < arr.length && arr[j] !== j + 1) {
      tmp = arr[i]
      arr[i] = arr[j]
      arr[j] = tmp
    } else {
      i++
    }
  }
  i = 0
  while (i < arr.length && arr[i] === i + 1) i++
  return i + 1
};

测试结果:

猜你喜欢

转载自blog.csdn.net/qq_39025670/article/details/104640549