41. 缺失的第一个正数
一、题目
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1
提示:
你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
二、题解
法1
-
使用nums数组自身作为存储空间进行数字统计,且时间O(n),具体方法参考448. 找到所有数组中消失的数字
- 正数——出现0次的数——缺少的数
- 负数——出现次数大于1的数——拥有的数
-
nums数组中的干扰项
- 负数,由于时负数是由含义的,因此如果初始就为负数,会将索引+1统计成拥有的数
- 大于nums.length的数,由于是将内容作为索引,数组本身的长度最多存从1~n的数
- 0既不是正数也不是负数,统计不到
- 因此将这些数都初始化为1——1~n的数都是可以的,只是其他数要多次进行判断
- 因为这些数的值对统计结果并没有影响,如[1,5,0]-->2 初始化后[1,1,1]--->2
-
但如果nums里初始没有1,初始化为1,1就会被统计为拥有,所以在初始化前需要先判断有没有1,没有1的情况下,一定缺少1,而最小正整数就是1,直接输出
-
特殊情况
- 数组长度为1,[1]---->2,[其余数]---->缺1都输出1
- 不缺数 [1,2,3]---->4,而存储后nums为[-1, -2, -3]---->1,因此要单独处理
-
图解——以[1,-2,10,2,-7]---->3为例
-
统计的数字 1 2 3 4 5 nums的索引 0 1 2 3 4 nums的元素 1 -2 10 2 -7 含1,初始化n=5 1 1 1 2 1 第一轮 -1 第二轮 --- 第三轮 --- 第四轮 -1 第五轮 --- 存储结果 -1 -1 1 2 1 -
第一个正数的索引+1——3
-
class Solution {
public int firstMissingPositive(int[] nums) {
int result = 0;
boolean have1 = false;
int sum = 0;
//特殊情况——数组长度为1
if (nums.length==1){
return nums[0]==1 ? 2 : 1;
}
//检查是否有1
for (int i = 0; i < nums.length; i++) {
if (nums[i]==1){
have1 = true;
}
}
//没有1的情况下一定输出1
if (!have1) {
return 1;
}
//确定有1的情况下,将干扰项都初始化为1
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (nums[i]<1 || nums[i]>nums.length) {
nums[i] = 1;
}
}
//特殊情况——不缺数
if (sum==(nums.length+1)*nums.length/2){
//和与正确总和相同如[1,3,2]
return nums.length+1;
}
//统计出现次数
for (int i = 0; i < nums.length; i++) {
//正数——出现0次的数——缺少的数
//负数——出现次数大于1的数——拥有的数
if (nums[Math.abs(nums[i])-1]>0) {
nums[Math.abs(nums[i])-1] *= -1;
}
}
//第一个正数的索引+1就是要找的数
for (int i = 0; i < nums.length; i++) {
if (nums[i]>0) {
return i+1;
}
}
return result;
}
}
-
时间复杂度O(n)
-
空间复杂度O(1)
-
执行用时:1 ms, 在所有 Java 提交中击败了87.34%的用户
-
内存消耗:36.3 MB, 在所有 Java 提交中击败了91.55%的用户
改进
- 由于特殊情况都列出了,因此当其余可能性都排除了,就只剩下不缺数的可能,因此不用sum处理
class Solution {
public int firstMissingPositive(int[] nums) {
int result = 0;
boolean have1 = false;
if (nums.length==1){
return nums[0]==1 ? 2 : 1;
}
for (int i = 0; i < nums.length; i++) {
if (nums[i]==1){
have1 = true;
}
}
if (!have1) {
return 1;
}
for (int i = 0; i < nums.length; i++) {
if (nums[i]<1 || nums[i]>nums.length) {
nums[i] = 1;
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[Math.abs(nums[i])-1]>0) {
nums[Math.abs(nums[i])-1] *= -1;
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i]>0) {
return i+1;
}
}
//最后一种情况——不缺数
return nums.length+1;
}
}
- 执行用时:1 ms, 在所有 Java 提交中击败了87.34%的用户
- 内存消耗:36.2 MB, 在所有 Java 提交中击败了92.80%的用户

浙公网安备 33010602011771号