BM53-缺失的第一个正整数
题目
给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数。
进阶: 空间复杂度 O(1),时间复杂度 O(n)。
数据范围:
−2^31≤nums[i]≤2^31−1。
0≤len(nums)≤5∗10^5。
示例1
输入:[1,0,2]
返回值:3
示例2
输入:[-2,3,4,1,5]
返回值:2
示例3
输入:[4,5,6,8,9]
返回值:1
思路1:哈希表
n个长度的数组,没有重复,则如果数组填满了1~n,那么缺失n+1,如果数组填不满1~n,那么缺失的就是1~n中的数字。对于这种快速查询某个元素是否出现过的问题,还是可以使用哈希表快速判断某个数字是否出现过。
具体做法:
- step 1:构建一个哈希表,用于记录数组中出现的数字。
- step 2:从1开始,遍历到n,查询哈希表中是否有这个数字,如果没有,说明它就是数组缺失的第一个正整数,即找到。
- step 3:如果遍历到最后都在哈希表中出现过了,那缺失的就是n+1。
代码1
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* @param nums int整型一维数组
* @return int整型
*/
public int minNumberDisappeared (int[] nums) {
int n = nums.length;
HashMap<Integer, Integer> mp = new HashMap<Integer, Integer>();
//哈希表记录数组中出现的每个数字
for(int i = 0; i < n; i++) {
mp.put(nums[i], 1);
}
int res = 1;
//从1开始找到哈希表中第一个没有出现的正整数
while(mp.containsKey(res)) {
res++;
}
return res;
}
}
- 时间复杂度:O(n),第一次遍历数组,为O(n),第二次最坏从1遍历到n,为O(n)。
- 空间复杂度:O(n),哈希表记录n个不重复的元素,长度为n。
思路2:原地哈希
前面提到了数组要么缺失1~n中的某个数字,要么缺失n+1,而数组正好有下标0~n−1可以对应数字1~n,因此只要数字1~n中某个数字出现,就可以将对应下标的值做一个标记,最后没有被标记的下标就是缺失的值。
具体做法:
- step 1:可以先遍历数组将所有的负数都修改成n+1。
- step 2:然后再遍历数组,每当遇到一个元素绝对值不超过n时,则表示这个元素是1~n中出现的元素,我们可以将这个数值对应的下标里的元素改成负数,相当于每个出现过的正整数,我们把与它值相等的下标都指向一个负数,这就是类似哈希表的实现原理的操作。
- step 3:最后遍历数组的时候碰到的第一个非负数,它的下标就是没有出现的第一个正整数,因为它在之前的过程中没有被修改,说明它这个下标对应的正整数没有出现过。
代码2
import java.util.*;
public class Solution {
public int minNumberDisappeared (int[] nums) {
int n = nums.length;
//遍历数组
for (int i = 0; i < n; i++) {
//负数全部记为n+1
if (nums[i] <= 0) {
nums[i] = n + 1;
}
}
for (int i = 0; i < n; i++) {
//对于1-n中的数字
if (Math.abs(nums[i]) <= n) {
//这个数字的下标标记为负数
nums[Math.abs(nums[i]) - 1] = -1 * Math.abs(nums[Math.abs(nums[i]) - 1]);
}
}
for (int i = 0; i < n; i++) {
//找到第一个元素不为负数的下标
if (nums[i] > 0) {
return i + 1;
}
}
return n + 1;
}
}
- 时间复杂度:O(n),多次遍历数组,都是单层循环。
- 空间复杂度:O(1),原地哈希,以索引为指向,没有额外空间。