题目描述:
在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。
答案:
# 方法一:借助辅助空间,输出全部重复的数字
import numpy as np
array = np.array([2,3,1,0,2,5,3,3])
def repeat(array):
b = []
length = len(array)
for i in range(length):
if array[i] in b:
# 返回已经存在的值
yield array[i]
b.append(array[i])
c = set(repeat(array))
print(c) #{2,3}
# 输出重复数字重复的次数
# c1 = list(repeat(array))
# for i in c:
# print(c1.count(i))
# 方法二:对原数组排序,遍历排序后的数组
import numpy as np
array = np.array([2,3,1,0,2,5,3])
def repeat(array):
length = len(array)
for i in range(length):
for j in range(i+1,length):
if array[j]<array[i]:
tmp = array[i]
array[i] = array[j]
array[j] = tmp
# print(array)排序后的数组
for i in range(length):
if i != array[i]:
return array[i]
c = repeat(array)
print(c) #{2}
# 方法三:牛客网可通过代码
'''
从头到尾依次扫描这个数组中的每个数字。当扫描到下标为i的数字时,首先比较
这个数字(用m表示)是不是等于i。如果是,则接着扫描下一个数字;如果不是,
则再拿它和第m个数字进行比较。如果它和第m个数字相等,就找到了一个重复的数
字(该数字在下标i和m的位置都出现了);如果它和第m个数字不相等,就把第i个
数字和第m个数字交换,把m放到属于它的位置。接下来重复这个比较、交换的过程,
直到我们发现一个重复的数字。
'''
# -*- coding:utf-8 -*-
class Solution:
def duplicate(self, numbers, duplication):
length = len(numbers)
if length == None:
return False
for index in range(length):
if numbers[index]<0 or numbers[index]>length-1:
return False
for index in range(length):
while index != numbers[index]:
if numbers[index] == numbers[numbers[index]]:#不同位置有相同值
duplication[0] = numbers[index]
return True
tmp = numbers[index]
numbers[index] = numbers[tmp]
numbers[tmp] = tmp
return False
#方法四
import collections
def repeat(numbers):
c = collections.Counter(numbers)
for k,v in c.items():
if v>1:
return k
numbers = [1,1,1,2,2,3,4]
print(repeat(numbers))
题目变形:
在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
'''
我们把从1~n的数字从中间的数字m分为两部分,前面一半为1~m,
后面一半为m+1~n。如果1~m的数字的数目等于m,则不能直接判断
这一半区间是否包含重复的数字,反之,如果大于m,那么这一半
的区间一定包含重复的数字;如果小于m,另一半m+1~n的区间里
一定包含重复的数字。接下来,我们可以继续把包含重复的数字
的区间一分为二,直到找到一个重复的数字。这个过程和二分查找
算法很相似,只是多了一步统计区间里数字的数目。
二分查找对象序列为1~n的有序序列,如题目中例子对应的二分查找
序列为{1,2,3,4,5,6,7}
'''
# 统计一定范围内有序序列元素在输入数组中出现的次数
def countRange(numbers,start,end):
if numbers == []:
return 0
count = 0
length = len(numbers)
for i in range(length):
if numbers[i]>=start and numbers[i]<=end:
count+=1
return count
def repeat(numbers):
if numbers == []:
return -1
length = len(numbers)
start = 1
end = length-1
while start <= end:
middle = (end+start)//2
count = countRange(numbers,start,middle)
if end == start:
if count>1:
return start
else:
break
if count>(middle-start+1):
end = middle
else:
start = middle+1
return -1
a = [2,3,5,4,3,2,6,7]
print(repeat(a))#3
上面的代码针对0~n-1的数组不适用,对其改进
def countRange(numbers,start,end):
if numbers == []:
return 0
count = 0
length = len(numbers)
for i in range(length):
if numbers[i]>=start and numbers[i]<=end:
count+=1
return count
def repeat(numbers):
if numbers == []:
return -1
length = len(numbers)
start = 0
flag = 0
end = length-1
while start <= end:
if flag == 0:
middle = start+((end-start)>>1)
count = countRange(numbers,start,middle)
if end == start:
if count>1:
return start
else:
break
if count>(middle-start+1):
end = middle
flag = 0
elif count == (middle - start + 1):
middle = middle - 1
if middle < start: #说明(start, middle)这个区间没有重复的数
start = (start+end) // 2 + 1
flag = 0
else:
flag = 1
else:
start = middle+1
flag = 0
return -1
a = [1,7,2,5,6,1,3,3]
b = [2,3,5,4,3,2,6,7]
print(repeat(b))