题目一:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7,的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数组2或者3。(n个元素,n种可能的取值)
解法一:先对数组进行排序,然后再查找排序后的数组中的重复元素
def selectedSort(lis): for i in range(0, len(lis)): minVal = lis[i] minInd = i #找出最小的元素 for j in range(i+1,len(lis)): if minVal>=lis[j]: minVal=lis[j] minInd=j #交换 lis[minInd]=lis[i] lis[i]=minVal return lis lis=[8,5,3,3,7,6,3,9,1,8] lis_order=selectedSort(lis) print(lis)
解法二:开辟一个新数组B,每次扫描源数组A中的元素,如果不在B中,就加入B中,如果在B中,就找到一个重复的元素
lisA=[8,5,3,3,7,6,3,9,1,8] def findDuplicates(lisA): lisB = [] for i in lisA: if i in lisB: print("找到一个重复的元素:%d"%i) break else: #当前扫描的元素不在lisB中,就加入到lisB中 lisB.append(i) continue findDuplicates(lisA)
解法三:因为列表总共有n个元素,所有元素可能取到的元素有0~n-1,共n种。如果不存在重复的数字,那么排序后数字i将会出现在下标为i的位置。现在让我们重新扫描数组,
- 当扫描到下标为i的数字时,首先比较这个数字(记为m)与i是否相等:
- 如果是,继续扫描下一个元素,
- 如果不是,则再拿它与第m个数字比较:
- 如果它和第m个数字相同,就找到了一个重复的元素;
- 如果不同,就将m与第m个数字互换。接下来继续重头开始,重复换这个比较。
lisA=[8,0,2,3,7,6,4,2,1,5] def findDuplicates(lisA): i=0 while i <len(lisA) and lisA!=[]: m = lisA[i] if m == i: i += 1 else: if m == lisA[m]: print('找到一个重复的元素:%d' % m) break else: temp = lisA[i] lisA[i] = lisA[m] lisA[m] = temp i = 0 findDuplicates(lisA)
题目二:
在一个长度为n+1的数组里的所有数字都在1~n范围内,所以数字中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或3。(n+1个元素,n种可能的取值)
解法一:同上题解法二,开辟一个大小为n+1的新数组
解法二:避免使用O(n)的辅助空间。我们把取值空间[1,n]从中间的数字m分为两部分,前面一部分为1~m,后面一部分为m+1~n。如果数组中元素落在前面一部分的元素个数多于m个,那么数组中重复的元素一定落在前半区间;否则,数组中重复的元素一定落在后半区间。然后,我们可以继续将包含重复元素的区间一分为二,直到找到一个重复的元素。
lisA=[8,1,2,3,7,6,7,4,9,5,10] def findDuplicates(lisA): """找到重复元素,返回True;否则,返回False""" low=1 high=len(lisA)-1 while low<=high: mid=(low+high)//2 #统计数组中落在前半部分区间中的元素的个数 count_low=0 for i in lisA: if i in range(low,mid+1): count_low+=1 #判断落在长度为1的区间中的数组元素个数 if high==low: if count_low>1: #如果大于1,则找到重复的元素 return low else: break #比较前半部分区间长度与落在该区间内元素的个数,决定将前半部分/后半部分区间继续一分为二 if count_low>(mid-low+1): high=mid else: low=mid+1 return False print(findDuplicates(lisA))