Date:
Nov. 1, 2017
Problem:
https://leetcode.com/problems/first-missing-positive/description/
Description:
Given an unsorted integer array, find the first missing positive integer.
For example,
Give [1, 2, 0], return 3 Give [3, 4, -1, 1] return 2
Your algorithm should run in O(n) time and uses constant space.
emmmmmm。
我有一个大胆的想法。
1 class Solution: 2 def firstMissingPositive(self, nums): 3 pst = list(range(2333333)) 4 for i in nums: 5 if i > 0: 6 pst[i] = 0 7 for i in pst: 8 if i > 0: 9 return i
本地测试,代码运行时间在200~300ms间。
提交,TLE。
一看数据,[1, 1, 1, 1, 1],不对劲呀。本地一跑,300ms,没问题。再提交,TLE。
认真看了看数据,发现前面已经过了一半测试点,不可能在这地方栽了。目测是反复运行同一函数累计时间超时了(和codewars一个尿性)。
1 class Solution: 2 def firstMissingPositive(self, nums): 3 pst = list(range(23333)) 4 for i in nums: 5 if i > 0: 6 pst[i] = 0 7 for i in pst: 8 if i > 0: 9 return i
提交,AC。
……
2333333。
正经的解法。
中心思想其实和计数排序有点像:把数放到它们该去的地方。
考虑一个长度为k的输入,它最多无死角覆盖1~k这些正整数,如果有大于k的数,1~k中显然会出现我们要找的missing positive。所以我们要做的事情就是将nums[1]~nums[k]放回它们该待的地方——如果放得进去的话(它们必须不能是负数或者超过k的数)。而当它们确实都覆盖了1~k时,我们要找的数就是k+1。
另一个更好理解的角度,k+1个抽屉,k个苹果,容斥原理。
所以我们令i=0~(k-1),检查每一个nums[i],当nums[i]在1到k之间(有位可放),nums[i] != nums[nums[i]-1](还没放入)时,我们就将nums[i]与nums[nums[i]-1]交换,将正确的数放入,不正确的数取出,不断重复此操作,直到发现nums[i]是无位可放的为止。
在操作过一遍之后,我们再度检查nums[i],返回第一个nums[i] != i+1(不正确)的数i+1。如果没有检查到,就返回k+1。
这个算法的复杂度为O(N)。
以下是submission。
1 class Solution: 2 def firstMissingPositive(self, nums): 3 k = len(nums) 4 for i in range(k): 5 while 0 < nums[i] <= k and nums[i] != nums[nums[i] - 1]: 6 nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1] 7 for i in range(k): 8 if nums[i] != i + 1: 9 return i + 1 10 return k + 1