题目
给定一个未排序的整数数组,找出其中没有出现的最小的正整数。
示例 1:
输入: [1,2,0]
输出: 3
示例 2:
输入: [3,4,-1,1]
输出: 2
示例 3:
输入: [7,8,9,11,12]
输出: 1
说明:
你的算法的时间复杂度应为O(n),并且只能使用常数级别的空间。
【困难】
【分析】设res=[1,2,…,n],如果res中的值在nums中存在,则res中的值赋值为负数;最后输出的结果在res中必定是正数,否则输出为n+1.
class Solution(object):
def firstMissingPositive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
if len(nums)==0:
return 1
n=len(nums)
res=range(1,n+1)
for i in range(n):
if nums[i]>0 and nums[i]<=n:
res[nums[i]-1]=-abs(res[nums[i]-1])
for i in res:
if i>0:
return i
return -i+1
【分析2】做一个官方解答的解析:通过nums的索引和符号来映射元素的值在不在nums中。具体地,
- 首先看1如果不在nums中:直接返回1;以下讨论的是1在nums中的情况:
- 看len(nums)==1(1在nums中):直接返回2;以下的情况要么res是n+1,要么res在1~n之间。
- n=len(nums) ,先处理小于等于0的数以及大于n的数,将这部分的数全部替换成1。
- 建立映射:nums的索引
i
i
i和元素的符号 ---- >正整数i是否存在于nums中,负号表示存在,正号表示不存在(注意这里nums元素的值本身对结果的输出没有什么影响)。具体地,也就是说nums中[1,…,n-1,n]的数都安排在nums的索引和元素的符号上,对应到python中数组的表示nums[0,n-1],索引1到n-1分别安排1到n-1的正整数,用索引0来安排正整数n。映射关系可以见下图,非常简单。
- 输出就是从索引1开始遍历到n-1,看nums中的符号如果有正,输出该索引值;最后遍历索引0(代表正整数n是否存在于nums中),若索引0中的value是正号此时返回n,否则返回n+1.
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
if 1 not in nums:
return 1
if len(nums)==1:
return 2
n=len(nums) #用元素的符号表示其是否存在:负号表示存在,正号表示不存在
#处理异常值
for i in range(n):
if nums[i]<=0 or nums[i]>n:
nums[i]=1
#映射
for i in range(n):
x=abs(nums[i])
if x==n:
nums[0]=-abs(nums[0])
else:
nums[x]=-abs(nums[x])
#输出
for i in range(1,n):
if nums[i]>0:
return i
if nums[0]>0:
return n
return n+1
我把以nums的符号和索引来映射结果改为了用res的索引和符号映射结果,哈哈~这样可以不用处理nums中小于等于0和大于n的数
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
if 1 not in nums:
return 1
if len(nums)==1:
return 2
n=len(nums) #用元素的符号表示其是否存在:负号表示存在,正号表示不存在
res=list(range(n))
for i in range(n):
if nums[i]>0 and nums[i]<n:
res[nums[i]]=-abs(res[nums[i]]) #用abs避免值出现重复比如2次的话,就会负负得正
print("y")
if nums[i]==n:
res[0]=-n
for i in range(1,n):
if res[i]>0:
return res[i]
if res[0]>=0:
return n
return n+1