符合题目的AC代码
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)
for i in range(n):
while nums[i] != i + 1 and nums[i] > 0 and nums[i] < n and nums[i] != nums[nums[i] - 1]:
#nums[i],nums[nums[i] - 1] = nums[nums[i] - 1],nums[i]
t1,t2 =nums[i],nums[nums[i] - 1]
nums[nums[i] - 1] = t1
nums[i] = t2
for i in range(n):
if nums[i] != i + 1:
return i + 1
return n + 1
不符合题目的AC代码
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
D = {}
for it in nums:D[it] = 1
i = 1
while i in D.keys(): i += 1
return i
分析
由于本题的时间复杂度要求为
O
(
n
)
O(n)
O(n),并且元素的取值范围为整数范围,所以最容易想到的处理方法便是借助哈希表——借助哈希表对每一个出现的值进行标记,每个取值的哈希时间为
O
(
1
)
O(1)
O(1),哈希的总复杂度为
O
(
n
)
O(n)
O(n)。然后在从1开始在哈希表中找出第一个没有出现的整数,该遍历过程的期望时间复杂度为
O
(
n
/
2
)
O(n/2)
O(n/2)。所以该过程的总时间复杂度为
O
(
n
)
O(n)
O(n),符合题目要求。然而,题目对于算法的空间复杂度同样有着严格的要求——
O
(
1
)
O(1)
O(1)的时间复杂度。
使用哈希表的空间复杂度是线性的,明显不符合题目的要求。
对于该题,使用哈希表多是一件美事,无奈哈希表的空间复杂度不达标,有什么优化的策略呢?
这里就要借助数据本身的一些特性了。
即借助数据本身的特殊性构建出一个特殊的哈希表,达到
O
(
1
)
O(1)
O(1)的复杂度要求。
如图所示,我们可以将每个数放到它应在的位置,最终的结果我们用
O
(
n
)
O(n)
O(n)的复杂度完成了对数值与数组下标的映射——即哈希。
需要注意的是,数组中数的取值可能为负数、也可能为很大的数。
对于这些数,我们可以不予理睬——因为数组长度只有n,所以缺失的第一个正数不可能大于n + 1。
我们是不是在用了
O
(
n
)
O(n)
O(n)的时间复杂度对一个数组进行了排序呢?
是的。
按照常规的认知,对于一个数组进行排序,最有的时间复杂度也得是
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n),为什么这里可以实现
O
(
n
)
O(n)
O(n)的排序呢?
那是因为我们借助了这个数组的特殊性——或者说是排序规则的特殊性——我们只对整数的有限范围内的数据进行排序,且排序时需要每个数不重复(否则该数会被忽略)。
题目链接
原创不易,感谢支持!