一、题目描述:
在一个长度为n的数组里,所有的数字都在0~n-1范围内。数组内某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复了几次,请找出数组中任意一个重复的数字。例如,如果输入数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或3
解题思路:
(1)思路一:排序。
最简单的思路就是将数组排序一下,然后排序完了从头遍历一遍,就可以知道重复的数字有哪些了,但是这样的时间复杂度是O(n*log n)。显然时间复杂度还是很高,那么有没有其他的方法可以更快一些呢?
(2)思路二:哈希表
第二种思路是我们可以从头到尾遍历一遍数组的时候,当遇到一个没有出现的数将其加入哈希表,这样我们每次做判断只需要O(1)的时间复杂度,再加上遍历一遍数组,总共的时间复杂度为O(n)。然而这样的方式虽然我们达到了时间复杂度被降低了,可是却浪费了一个大小为O(n)的哈希表为代价的。那么还有更好的方法还能再降低空间复杂度吗?
(3)思路三:充分利用数组的下标
注意题目说长度为n的数组中,所有的数字都是再0~n-1之间的,也就是说这里面每一个的数字都可以当作数组的下标使用(而不会越界),那么我们的思想就可以是将每个数字放在自己对应的下标的地方,当有个数字准备去自己的下标的地方的时候,如果发现那个地方以及有一个和他一模一样的数字待在那里,那么就断定这个数字重复了。这样我们的时间复杂度就是遍历一遍数组为O(n),空间复杂度也降低在了此数组中,为O(1)。
下面我们那题目的例子列出思维的步骤:
为了叙述方便,我们改造一下数组[2,0,1,2,3]:
- 发现下标为0的位置的数不是0,而是2。做交换操作,把2送回下标为2的位置。(此时数组变成了[1,0,2,2,3])
- 发现此时下标为0处的数字仍然不是0,那么又送1回下标为1的位置。(数组变为[0,1,2,2,3])
- 此时current为0,发现此时0下标处的数字为0,current += 1
- 此时current为1,发现此时1下标处的数字为1,current += 1
- 此时current为2,发现此时2下标处的数字为2,current += 1
- 此时current为3,发现此时3下标处的数字不是3,而是2,而把2送回下标为2的地方的时候发现那里以及有一个2了,于是返回2重复(此时跳出程序即可满足题目要求了)
二、代码实现:
def searchRepetitiveNumber(arrayOne):
length = len(arrayOne)
current = 0
while current < length:
if arrayOne[current] == current:
current += 1
elif arrayOne[current] != arrayOne[arrayOne[current]]:
#交换操作
flag = arrayOne[current]
x,y = arrayOne[current],arrayOne[arrayOne[current]]
arrayOne[flag] = x
arrayOne[current] = y
else:
print("%d is repetitive!" % arrayOne[current])
current += 1
print("over!")
if __name__ == '__main__':
arrayOne = [9,8,7,6,5,7,6,5,4,0]
if not isinstance(arrayOne,list):
print("input wrong!")
else:
searchRepetitiveNumber(arrayOne)
注意:交换操作的代码不可以写成:
arrayOne[arrayOne[current]] , arrayOne[current] = arrayOne[current] , arrayOne[arrayOne[current]]
详情请看我的另一篇博客《你真的知道a,b = b,a是怎么实现的吗?(python交换逻辑)》.
I am very glateful that 你看到这里了哦~下回再见ヾ(o◕∀◕)ノヾ
Thx