数组中重复的数字
题目一描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
解题思路
思路一
排序
- 给定的数组是乱序的,我们首先对数组排序,然后遍历数组对比一下就可以找到重复的那个数字了。
- 时间复杂度O(nlogn)
python实现代码
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
# write code here
if numbers is None or len(numbers) == 0:
return False
for i in numbers:
if i < 0 or i >= len(numbers):
return False
numbers.sort()
for i in range(len(numbers)-1):
if numbers[i+1] == numbers[i]:
duplication[0] = numbers[i]
return True
return False
思路二
哈希表
- 上述算法在时间上还可以进行优化,空间换时间。我们另外采用一个哈希表来保存数字和其出现的次数。
- 时间复杂度O(n),空间复杂度o(n)
python实现代码
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
# write code here
if numbers is None or len(numbers) == 0:
return False
for i in numbers:
if i < 0 or i >= len(numbers):
return False
lookup = {}
for num in numbers:
if num in lookup:
duplication[0] = num
return True
lookup[num] = 1
return False
思路三
哈希表
- 继续优化,能不能找到不需要额外空间的算法?
- 我们注意到,如果数组中的元素没有重复的,那么排序之后数字i会出现在数组下标为i的位置。现在我们有重复的数组,所以有些位置可能存在多个数字,有一些位置可能没有数字。
- 首先从头至尾扫描数组,当扫描到位置i时,比较这个数字(m)是不是等于i,如果是,则接着扫描下一位;如果不是,则再拿它和第m个数字进行比较,如果相等,就找到了重复的数字;如果不相等,就交换两个数字,把m放到属于它的位置。接下来重复这个过程直到发现第一个重复的数字
- 时间复杂度O(n),空间复杂度o(1)
python实现代码
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers, duplication):
# write code here
if numbers is None or len(numbers) == 0:
return False
for i in numbers:
if i < 0 or i >= len(numbers):
return False
for i in range(len(numbers)):
while numbers[i] != i:
if numbers[i] == numbers[numbers[i]]:
duplication[0] = numbers[i]
return True
# swap
tmp = numbers[numbers[i]]
numbers[numbers[i]] = numbers[i]
numbers[i] = tmp
return False
题目二描述
在一个长度为n+1的数组里的所有数字都在1到n的范围内。 所以数组中至少有一个数字是重复的请找出数组中任意一个重复的数字,但不能修改输入的数组。 例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
解题思路
思路一
二分查找
- n+1长度的数组中有1n的数,所以至少有一个数是重复的。要找出那个数字,我们可以按照二分查找的思路,将1n分成1m和m+1n两部分。如果1~m的数字的数目超过m,那么这一半区间一定包含了重复数字;反之则在另外一半。
- 如果输入长度为n的数组,函数countNum将被调用Logn次,每次需要O(n)时间,因此总的时间复杂度O(nlogn),空间复杂度O(1)。
python实现代码
class Solution:
# 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
# 函数返回True/False
def duplicate(self, numbers):
# write code here
if numbers is None or len(numbers) == 0:
return False
length = len(numbers)
l, r = 0, length-1
while l <= r:
mid = (l +r) // 2
count = countNum(numbers, length, l, mid)
if l == r:
if counr > 1:
return True
else:
break
if count > mid - l + 1:
r = mid
else:
l = mid + 1
return False
def countNum(numbers, length, l, r):
if numbers is None:
return 0
count = 0
for i in range(length):
if l <= numbers[i] <= r:
count += 1
return count