1.题目
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
1
2
示例 2:
输入: [3,1,3,4,2]
输出: 3
1
2
说明:
不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Example 1:
Input: [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2]
Output: 3
Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.
2.1二分法思路
我们首先想到的解法就是先将数组nums排序,建立pre和cur两个指针,分别指向前面一个元素和当前元素,然后对于排序好的nums从头到尾的遍历,判断nums[pre]==nums[cur],如果成立,返回nums[pre]即可,否则的话继续遍历。
class Solution:
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums.sort()
for i in range(len(nums)-1):
if nums[i] == nums[i+1]:
return nums[i]
但是我们这种做法改变了原有的数组,所以这种做法就被我们排除了。由于是查找问题,我们不难想到通过二分搜索法,但是这里我们要将原来的二分搜索法做一些调整。我们首先计算mid,然后我们统计数组中小于等于mid元素的个数k,如果k<=mid的话,那么说明重复值在[mid+1,n]之间,否则的话重复值在[1,mid]之间。为什么这样子做是合理的呢?实际上这个问题的思想来源于抽屉原理,我们将包含重复元素的所有数放到一个可以容纳所有数的数组中去,如下
class Solution:
def findDuplicate(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
low, high = 1, len(nums)-1
while low < high:
mid = low + (high-low)//2 #防止溢出
count = sum(num <= mid for num in nums)
if count <= mid:
low = mid+1
else:
high = mid
return low