题目
数组长度为n + 1,数组中的数大小均在1~n的范围内,则数组中至少会存在一个重复数字。要求找出其中一个重复数组。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出重复的数字是2或者3,输出其中一个即可。
思路1:可直接将数组排序,遍历数组,找到其中一个重复数字即可。时间复杂度是O(nlogn)。
def findDuplicates(nums):
if not nums: return None
nums = sorted(nums)
for i in range(len(nums) - 1):
if nums[i] == nums[i + 1]:
return nums[i]
思路2:引入集合,集合中是数组中所有出现过的数字,遍历集合,若集合中的该元素出现在数组中,则在数组中移除该元素(重复的元素只会移除第一个该元素)。则数组中剩下的数均为重复的数。时间复杂度是O(n^2),空间复杂度是O(n)。
def findDuplicates(nums):
if not nums: return None
numset = set(num)
for x in numset:
if x in nums: nums.remove(x)
if not nums: return None
return nums[0]
思路3:开辟一个长为n的数组count,用于标记数字出现的次数,若count[n]>1,说明出现次数大于1.时间复杂度为O(n),空间复杂度也为O(n)。
def findDuplicates(nums):
if not nums: return None
count = [0] * (len(nums))
for x in nums:
count[x] += 1
for x in count:
if x > 1: return x
return None
思路4:可采用二分的方式,遍历数组,统计小于n/2的值的个数,若个数大于n/2,说明重复的数出现在1~n/2里,否则出现在n/2~n里。以此继续二分下去,直至找到一个重复的数。时间复杂度O(nlogn),空间复杂度O(1)。
def findDuplicates(nums):
if not nums: return None
left, right = 1, len(nums) - 1
while left < right:
mid = left + (right - left) // 2
for x in nums:
if x <= mid: count += 1
if mid < count: right = mid
else: left = mid + 1
return left
思路5:重排数组的方式,使得nums[i] = i,遍历数组,如果nums[i] == i说明nums[i]的位置正确,继续遍历,否则,把nums[i]放到正确的位置上,若该位置上的值已有nums[i]了,说明nums[i]为重复元素。时间复杂度O(n),空间复杂度O(1)。
def findduplicates(nums):
if not nums: return None
for i in range(len(nums)):
while nums[i] != i:
if nums[nums[i]] == nums[i]: returnn nums[i]
else: nums[nums[i]], nums[i] = nums[i], nums[nums[i]]
return None
题目另一版:长度为n+1的数组,每个数字的范围在0~n,数组中可能会存在重复数字,若存在,找出其中一个重复数字。
数字范围在0~n,此时数组中可能不存在重复数字,因此可以采用思路5数组重排的方式来解决。
def findduplicates(nums):
if not nums: return None
for i in range(len(nums)):
while nums[i] != i:
if nums[nums[i]] == nums[i]: returnn nums[i]
else: nums[nums[i]], nums[i] = nums[i], nums[nums[i]]
return None