题目:给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
输入: [1,2,0] 输出: 3
输入: [3,4,-1,1] 输出: 2
方法1. 排序之后 顺序遍历 时间: 取决于排序算法 空间: 常数
方法2. 构造Hash表 时间: O(n) 空间: O(n)
注意Hash表不一定要用hashMap 可以先找数组的规律: 第一个缺失值(ans)最大是len+1
因为: 1 2 3 4 长度是4 ans是5,如果还有一种情况使得ans>5 那么5一定在数组中出现,那么5会替换1234中的任一个, 假如替换2, 那么2就变成第一个缺失值了,轮不到5了。
所以hash表可以设置 new int[len + 1] 就行
方法3. 数组元素的符号(+、-) 充当hash,只是改变原有值的正负号,绝对值没有改变
基于方法2可知: ans不会超过len+1 算法流程:
- 将负数,零,和大于 len+1 的数替换为 len+1。(去除无用的值,还能保证使用nums[i]做索引不会越界)
- 遍历数组。当前值num的绝对值|num|作为索引index,如果index<=len 令nums[index-1] 的值变为负值
- 再次遍历数组。返回第一个正数元素的索引+1。如果提前没有返回 说明ans是len+1。
第2步: 之所以nums[i]取绝对值, 是因为可能提前被置为负数了, 之所以不是取反,因为可能有重复偶数个的num
在第2步结束,nums[i] < 0 说明 i+1 出现了
第3步: 之所以返回索引+1 是因为改变的是nums[index-1] ,index索引左移了一位 保证0索引位置也被考虑
public int firstMissingPositive(int[] nums) {
int len = nums.length;
for (int i = 0; i < len; ++i) {
if (nums[i] <= 0 || nums[i] > len + 1)
nums[i] = len + 1;
}
for (int num : nums) {
int index = Math.abs(num);
if (index <= len)
nums[index - 1] = -Math.abs(nums[index - 1]);
}
for (int i = 0; i < len; ++i)
if (nums[i] > 0) return i + 1;
return len + 1;
}