问题一:找出数组中重复的数字
描述:
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为 7 的数组 [2,3,1,0,2,5,3] ,那么对应的输出是 2 或者 3 。存在不合法的输入的话输出 -1 。
实例:
输入:[2,3,1,0,2,5,3]
返回值:2
说明:2 或 3 都是对的
方法1:利用字典(哈希表)。从头到尾扫描数组的每个数字,每扫描到一个数字时,都可以用 O(1) 的时间判断字典中是否已经包含了该数字。如果没有,就把它加入到字典中;否则,就找到了一个重复数字。时间复杂度为 O(n) ,空间复杂度为 O(n) 。
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param numbers int整型一维数组
# @return int整型
#
class Solution:
def duplicate(self , numbers ):
# write code here
dict1 = {}
if not numbers:
return -1
for i in numbers:
if dict1.get(i) == i:
return i
else:
dict1[i] = i
方法2:下标定位法。由于数组中的数字都在 0 到 n-1 的范围内,如果这个数组中没有重复的数字,那么当数组排序后数字 i 将出现在下标为 i 的位置。首先从头到尾扫描这个数组中的每个数字,当扫描到下标为 i 的数字时,首先比较这个数字即 numbers[i] 与 i 是否相等,如果是,则接着扫描下一个数字;如果不是,再拿 numbers[i] 和 numbers[numbers[i]] 进行比较,若相等,则找到了一个重复的数字(该数字在下标为 i 和 numbers[i] 的位置都出现了);否则,就把第 i 个数字和第 numbers[i] 个数字交换,把 numbers[i] 放在属于他的位置上(即numbers[numbers[i]])。时间复杂度为 O(n) ,空间复杂度为 O(1) 。
class Solution:
def duplicate(self , numbers ):
# write code here
if not numbers:
return -1
i = 0
while i < len(numbers):
if i == numbers[i]:
i += 1
else:
if numbers[i] == numbers[numbers[i]]:
return numbers[i]
else:
temp = numbers[i]
numbers[i] = numbers[temp]
numbers[temp] = temp
问题二:不修改数组找出重复的数字
描述:
在一个长度为 n+1 的数组里的所有数字都在 1 到 n 的范围内,所以数组中至少有一个数字时重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。 例如,如果输入长度为 8 的数组 [2,3,5,4,3,2,6,7] ,那么对应的输出是 2 或者 3 。
实例:
输入:[2,3,1,0,2,5,3]
返回值:2
说明:2 或 3 都是对的
方法1:利用字典,与问题一一样。
方法2:为了避免 O(n) 的辅助空间。数字在 1 到 n 的范围内只有 n 个数字,但数组包含了 n+1 个数字,因此肯定有重复的数字。将数组按中位数划分为两组进行个数统计,小于或小于等于中位数的数字统计为一组,大于中位数的统计为一组,两组中,若有数字个数大于中位数,则说明该组中存在重复的数字,然后将该组视为新的数组,重新计算中位数并统计,直至找到一个重复的数字。类似于二分查找算法。时间复杂度为 O(nlogn) ,空间复杂度为 O(1)。
class Solution:
def duplicate(self, numbers):
length = len(numbers)
if not numbers and length < 2:
return -1
left = 1
right = length - 1
while left < right:
mid = (left+right) //2
count = 0
for i in numbers:
if i <= mid:
count += 1
if count > mid-left+1:
right = mid
else:
left = mid + 1
return left