题目描述:
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
示例 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
};
测试结果: