3-1. 数组中重复的数字
题目描述:
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
代码:
def duplicate(nums):
for i, num in enumerate(nums):
while i != num:
if num == nums[num]:
return True, num
else:
nums[i], nums[num] = nums[num], nums[i]
num = nums[i]
return False, None
思路描述:
由于数组中的数字都在 的范围内,因此如果这个数组中没有重复的数字,那么当数组排序之后数字 将出现在下标为 的位置。而由于数组中有重复的数字,那么有些位置可能存在多个数字,同时有些位置可能没有数字。
基于这种考虑,我们从头到尾遍历数组中的每个数字。当遍历到下标为 的数字时,首先比较这个数字(用 表示)是不是等于 。如果是,就表明这个数字位于本来就属于它的位置;如果不是,那我们把它和第 个位置上的数字进行比较。如果它等于第 个位置上的数字,那就找到了一个重复的数字;如果不等,那就把它和第 个位置上的数字交换。这样一来,第 个位置上的数字就跑到了第 个位置上。然后继续比较这个下标 上的数字,直到这个位置上的数字等于 ,才进行下一个位置上的数字比较。
复杂度分析:
- 时间复杂度:代码中尽管有一个两重循环,但每个数字最多只要交换两次就能找到属于它的位置,因此总的时间复杂度是 ;
- 空间复杂度:所有的操作都是在输入数组上进行的,不需要额外分配内存,因此空间复杂度是 。
3-2.不修改数组找出重复的数字
题目描述:
在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或者3。
代码:
def find_duplicate(nums):
def count_range(i, j):
return sum(i<=num<=j for num in nums)
lo = 1
hi = len(nums) - 1
while lo <= hi:
mid = (lo + hi) // 2
count = count_range(lo, mid)
if lo == hi:
if count > 1:
return lo
else:
break
if count > mid-lo+1:
hi = mid
else:
lo = mid + 1
return None
思路分析:
假如没有重复的数字,那么在 1~n 的范围内最多只能有 n 个数字,而现在数组中有 n+1 个数字,就表明至少肯定是在某个范围内多了一个数字,那么我们就可以根据某个范围内数字的个数来判断是否有重复的数字。
把原数组从中间二分,假设中间数字是 m,那么左边一半即为 1~m,右边一半为 m+1~n。如果左边一半的数字个数超过了 m,就表明在这个区间里一定包含了重复的数字;否则,右边的一半区间里一定包含了重复的数字。然后,我们对包含重复数字的区间继续二分,如此进行下去,直到最终找到重复的数字。
复杂度分析:
- 时间复杂度:如果输入长度为 n 的数组,那么函数
count_range
将被调用 次,每次都需要 的时间,因此总的时间复杂度是 ; - 空间复杂度:
网友评论