41.缺失的第一个正数
题目描述
给你一个未排序的整数数组,请你找出其中没有出现的最小的正整数。
示例:
输入: [1,2,0]
输出: 3
输入: [3,4,-1,1]
输出: 2
输入: [7,8,9,11,12]
输出: 1
提示:你的算法的时间复杂度应为O(n),并且只能使用常数级别的额外空间。
(确定这是提示,不是进阶要求???好吧我是真的小白)
我的思路(小白思路)
先将数组排序,然后定义一个key。key的初值设为1,利用二分查找在排序后的数组中找key。如果找到了,则key = key+1,并对比key和数组中下一个数是否相等,直到不等的时候或者遍历完剩余数组,则当前key就是第一个缺失的正数;如果没找到直接返回key,就是缺失的。
时间复杂度太高了,可是居然跑过了,神奇。
def firstMissingPositive(self, nums: List[int]) -> int:
nums = sorted(set(nums))
key = 1
def find(nums,key): #二分查找
left = 0
right = len(nums)-1
while left <= right:
mid = (left+right)//2
if nums[mid] == key:
return mid
elif nums[mid] < key:
left = mid+1
else:
right = mid-1
return -1
pos = find(nums,key)
if pos != -1:
nums = nums[pos+1:]
key += 1
for x in nums:
if x == key:
key += 1
else:
return key
else:
return 1
return key
官方思路(感觉是有点牛逼的)
官方思路里要用到类哈希表的思路,而我又是一个小白,并不清楚什么是哈希表。官方题解没说到哈希表需要排序,不知道这是不是哈希表的特殊性质,看来要补充一下关于哈希表的知识。
哈希表:可以支持快速查找的数据结构;给定一个元素,我们可以在 O(1) 的时间查找该元素是否在哈希表中。
具体的思路妙在将数组改成类哈希表的样子。首先需要明确:如果给定的数组长度为n的话,那么我们要找的数一定在[1, n+1]这个区间内。原因:左边界为1闭区间,因为是正整数;右边界为n+1闭区间,考虑最坏情况,即数组中的数都是连续的正整数,且从1开始,则我们要找的数就是n+1,因为是最坏情况,所以这就是要找的数的最大可能值。其他情况,比如非连续的正整数数组,或者连续但是并不从1开始,要找的值一定在[1, n+1]中。
具体算法流程如下:
1. 先遍历整个数组,将所有非整数都修改为n+1
2. 遍历数组,每次遍历取当前值x的绝对值|x|,如果|x|落在[1, n]内,则将数组内|x|-1位置上的数标记为负(-1是因为数组的位置从0开始记),如果已为负数则不再重复标记。这里要用绝对值而不是取原值的意义在于,遍历中每一次取的数有可能已经被标记过了,所以用|x|。
3. 最后再看修改后的数组,第一个正数出现的位置pos,pos+1就是我们要找的那个正整数。
4. 如果所有数都被标记,则表明这个数组是连续且从1开始的,则输出n+1。
思路理解:我们将数组内所有的|x|作为位置,并将相应位置上(|x|-1)的数标记为负,这种做法相当于将当前数组进行了一种排序,即这个数组如果进行排序,且数组的最小值如果为1的话(即最坏情况,上文提到的整个数组连续但乱序且从1开始),当前所取的值(满足在[1, n])应该在的位置,我们其实是将这个位置标记为负。那么如果有位置没有被标记,则这个位置在排序后所存在的数自然就是缺失的那个。当然,如果全都被标记了,那么就是不缺失,取n+1就好。(只是个人理解,不一定对,欢迎指正)
时间复杂度:O(n) 空间复杂度:O(1)
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)
for i in range(n):
if nums[i] <= 0:
nums[i] = n+1
for x in nums:
if abs(x) >=1 and abs(x) <= n and nums[abs(x)-1] > 0:
nums[abs(x)-1] = -nums[abs(x)-1]
for i in range(n):
if nums[i] > 0:
return i+1
return n+1
官方题解的思路二和上面的思路大同小异,只不过将打标记变为了直接换位置,可能更直观吧。简单来说就是位置变换后数组内位置i上的数字应该为i+1;若不是,说明缺失。感觉比以上的思路要稍麻烦一点点,毕竟换位置不像打标记那么简单。
以上就是我,一个正儿八经的小白(大神们通过看代码应该也感觉出来了),对这道题的理解,欢迎诸位指正讨论,感谢阅读。
原题链接:
https://leetcode-cn.com/problems/first-missing-positive/