给你一个未排序的整数数组
nums,请你找出其中没有出现的最小的正整数。请你实现时间复杂度为
O(n)并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。
解法1 set辅助
思路
在不考虑辅助空间的情况下,要想找出最小的正整数,可以把所有的数字放入 set 中。然后从 1 开始遍历 set,如果存在,那么遍历自增,直到 set 不包含这个数。
代码
function firstMissingPositive(nums: number[]): number {
const hashSet: Set<number> = new Set(nums);
let missing = 1;
while (hashSet.has(missing)) {
missing += 1;
}
return missing;
};
时空复杂度分析
时间复杂度:在生成 set 时顶多遍历一遍,总共两次遍历,所以复杂度为 O(n)
空间复杂度:有 set 的额外辅助空间 O(n)
解法2 原地哈希
思路
上一种解法使用了额外的空间,要想不使用额外空间,可以将这个数组本身抽象成一个 set,让数组本身呆在对应的下标。比如数字 1 应该在索引 0 的位置,数字 2 应该在索引 1 的位置,以此类推。再次遍历即可找出最小的正整数。
代码
function firstMissingPositive(nums: number[]): number {
const n: number = nums.length;
for (let i = 0; i < n; i++) {
while (
nums[i] > 0 && // 首先是正整数
nums[i] <= n &&
// 其次要在数组长度里。如果特别大,那么没必要换
// 因为找的是最小的数,即使全部遍历完毕都存在,那么最小的其实是 n + 1
nums[i] != nums[nums[i] - 1]
// nums[i] - 1代表了下标i的数,减一是因为从1放在0的下标(寻找正整数。从1开始)
// 检查当前数字 nums[i] 是否在正确位置,即下标为 nums[i] - 1 的位置
) {
let temp:number = nums[nums[i] - 1];
nums[nums[i] - 1] = nums[i];
nums[i] = temp;
}
}
for (let i = 0; i < n; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
}
return n + 1;
};
时空复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)