这个问题看起来很简单,很容易想到以下三种解法:
解法 | 时间 | 空间 |
---|---|---|
两重循环 | n 2 n^2 n2 | 1 |
先排序,再遍历 | n log n n\log n nlogn | 1 |
哈希表 | n | n |
但如果继续问,还有没有更高效的算法呢?
比如时间复杂度是 O ( n ) O(n) O(n), 空间复杂度为 O ( 1 ) O(1) O(1) 的算法?
😏😏😏
还真有!!
但是对 数组 有几个要求:
- 数组元素都是正数
- 数组是可写的
- 数组元素的最大值小于数组的长度
满足了以上三点。我们就可以使用下面这个算法了
def CheckDuplicates(A):
for i in range(0, len(A)):
if(A[abs(A[i])] < 0):
return abs(A[i])
else:
A[abs(A[i])] *= -1
return None
A = [3, 2, 1, 4, 2, 3]
print(CheckDuplicates(A)) # 2
咱们来看看具体的过程:
循环 | 数组状态 |
---|---|
原始 | [ 3 , 2 , 1 , 4 , 2 , 3 ] [3, 2, 1, 4, 2, 3] [3,2,1,4,2,3] |
i=0 | 把第 A [ 0 ] A[0] A[0]个元素取负, A = [ 3 , 2 , 1 , − 4 , 2 , 3 ] A= [3, 2, 1, -4, 2, 3] A=[3,2,1,−4,2,3] |
i=1 | 把第 A [ 1 ] A[1] A[1]个元素取负, A = [ 3 , 2 , − 1 , − 4 , 2 , 3 ] A= [3, 2, -1, -4, 2, 3] A=[3,2,−1,−4,2,3] |
i=2 | 把第 A [ 2 ] A[2] A[2]个元素取负, A = [ 3 , − 2 , − 1 , − 4 , 2 , 3 ] A= [3, -2, -1, -4, 2, 3] A=[3,−2,−1,−4,2,3] |
i=3 | 把第 A [ 3 ] A[3] A[3]个元素取负, A = [ 3 , − 2 , − 1 , − 4 , − 2 , 3 ] A= [3, -2, -1, -4, -2, 3] A=[3,−2,−1,−4,−2,3] |
i=4 | 发现第 A [ 4 ] A[4] A[4]个元素已经是负数,说明之前有元素和 A [ 4 ] A[4] A[4] 相同,所以找到了重复元素 |
上述算法的本质是把原始数组用作计数器,节省了额外的空间,但是要求元素的取值范围在数组的长度范围之内,否则就没法对它计数了。
上述算法实现了时间复杂度是 O ( n ) O(n) O(n), 空间复杂度为 O ( 1 ) O(1) O(1) 的算法,还是非常巧妙滴 🤓