题目描述:
在一个长度为n的数组里的所有数字都在1-n范围内,数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数字中任意一个重复的数字。前提条件是不能修改数组
哈希表法:
建立一个全部为0值,长度为 n 的哈希表,如果没有重复数字,哈希表中所有的值全部为1,不存在第二次赋值为1的情况
1-从头到尾扫描原数组Lst,下标为i的位置上对应的数字是m
2-判断哈希表中下标为m的位置上值是否为0
3-为0,将数组数字m放到哈希表中,即令哈希表总对应的值为1(1是这里的一个标记值,用来判断)
表示哈希表中下标为m的位置上没有对应值,即原列表中第一次出现数字m
4-为1,返回数字m,数字m为重复的数字。
因为哈希表中已经存在数字m,在此基础上原列表i位置上又出现了数字m,数字m为重复的数字
如果避免使用O(n)的空间消耗,可以使用二分法查找算法,但是增加了一个统计数字出现的个数过程.
二分查找算法+统计区间数字
- 将1-n数字分为两部分: startN—midN 和 midN—endN两部分 即 1—m 和 m+1—n两部分
如果1—m区间内的数字超过了m,那么这一半的区间内一定存在重复的数字;否则另外一半一定存在重复的数字。我们可以继续将包含重复数字的区间一分为二,直到找到重复的数字。
- 找到重复的数字:当数字范围startN == endN的时候,判断该数字出现的次数超过1,则找到重复数字返回该数字startN.
- 最后剩下两个数字 3,4 由于整除的计算,最后找到重复数字时,对应的情况是startN == endN
'''
Creat by HuangDandan
2018-08-24
dandanhuang@sjtu.edu.cn
'''
#哈希表 需要额外的空间,空间消耗为O(n)
import numpy as np
def HashFind(a): #哈希表 需要额外的空间,空间消耗为O(n)
num_array = np.zeros(len(a))
for i in range(len(a)):
if num_array[a[i]] == 0:
num_array[a[i]] += 1
else:
return a[i]
#二分法查找统计思想
#数值范围1-n,一共n-1个数字
#循环实现,循环改变索引值进行二分:
def getDuplication(a):
m = len(a)
startN = 1 #列表数值范围最小值
endN = m #列表数值范围最大值
while startN <= endN:
midN = (startN+endN)>>1 #二分法中间值
numbers = 0
for i in range(m):
if (a[i]<= midN) & (a[i]>= startN):
numbers += 1
if numbers > (midN - startN+1): #关键(midN - startN+1),如果没有重复元素,startN与midN范围间相差的数字个数
startN, endN = startN, midN
else:
startN, endN = midN+1, endN
if startN == endN: #最后判断数组出现的次数
number = 0
for j in a:
if j ==startN:
number += 1
if number > 1:
return startN
else:
break
return False
if __name__ == "__main__":
Lst2 = [2,2,3,4,6,6]
Lst3 = [1,2,3,4,6,4,6]
Lst4 = [2,5,4,2,5,3]
Lst5 = [1, 0]
print(Lst2)
print("----------------------------------------")
#print(HashFind(Lst2))
print(getDuplication(Lst2))
温故:
对于二分法思想+统计数字的方法:
当1—m区间范围,数组中该范围的数字出现的次数等于m时,应该怎么处理。理论上说可能存在重复数字也可能不存在。