解法一:将数组视为哈希表,原地哈希
由于题目要求我们「只能使用常数级别的空间」,而要找的数一定在 [1, N + 1] 左闭右闭(这里 N 是数组的长度)这个区间里。因此,我们可以就把原始的数组当做哈希表来使用。事实上,哈希表其实本身也是一个数组;
我们要找的数就在 [1, N + 1] 里,最后 N + 1 这个元素我们不用找。因为在前面的 N 个元素都找不到的情况下,我们才返回 N + 1;
那么,我们可以采取这样的思路:就把 1 这个数放到下标为 0 的位置, 2 这个数放到下标为 1 的位置,按照这种思路整理一遍数组。然后我们再遍历一次数组,第 1 个遇到的它的值不等于下标的那个数,就是我们要找的缺失的第一个正数。
这个思想就相当于我们自己编写哈希函数,这个哈希函数的规则特别简单,那就是数值为 i 的数映射到下标为 i - 1 的位置。
func firstMissingPositive(nums []int) int {
// 不能用for range,因为其迭代时,i是按顺序递增的,不会回溯,无法模拟交换后继续检查的行为
// for range 迭代的 nums[i] 是副本,即使交换了 nums[i],也不会影响 range 的下一次迭代逻辑
for i:=0; i<len(nums); i++{
// 将nums[i]置换到下标为nums[i]-1的位置上,可能需要多次置换后才成功,因此是个循环
for nums[i] > 0 && nums[i] < len(nums) && nums[i] != nums[nums[i]-1]{
nums[i], nums[nums[i]-1] = nums[nums[i]-1], nums[i]
}
}
// 找到第一个值不等于下标+1的位置
for idx, v := range nums{
if idx + 1 != v{
return idx + 1
}
}
// 如果整个数组都找不到对应不上的,那么缺失的就是len+1
return len(nums) + 1
}