题目
给定一个长度为 n+1n+1 的数组nums,数组中所有的数均在 1∼n1∼n 的范围内,其中 n≥1n≥1。
请找出数组中任意一个重复的数,但不能修改输入的数组。
数据范围 1≤n≤10001≤n≤1000 样例 给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。
返回 2 或 3。 思考题:如果只能使用 O(1)O(1) 的额外空间,该怎么做呢?
解析
抽屉原理:n + 1个球放到n个抽屉里,必然会有一个抽屉中球的个数大于等于2。
根据抽屉原理,然后利用二分的思想,将数取值的区间[1, n]分成[1, n/2]和[n/2, n],分别统计每个区间中数的个数,若有哪个区间数的个数大于等于区间长度,取的数一定在这个区间内,此时就将范围缩减到一半,然后依次进行下去,直到区间长度==1时,就得到最后的结果。
代码
C++
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int l = 1, r = nums.size() - 1;
while (l <= r) {
int s = 0;
int mid = l + (r - l) / 2;
for (auto x: nums)
s += x >= l && x <= mid;
if (s > mid - l + 1) r = mid - 1;
else l = mid + 1;
}
return l;
}
};
Python
class Solution(object):
def duplicateInArray(self, nums):
"""
:type nums: List[int]
:rtype int
"""
l, r = 1, len(nums) - 1
while l <= r:
mid = (l + r) // 2
s = 0
for x in nums:
if x >= l and x <= mid:
s += 1
if s > mid - l + 1:
r = mid - 1
else:
l = mid + 1
return l
Go
func duplicateInArray(nums []int) int {
l, r := 1, len(nums) - 1
for l <= r {
mid := l + (r - l) / 2
s := 0
for _, v := range nums {
if v >= l && v <= mid {
s += 1
}
}
if s > mid - l + 1 {
r = mid - 1
} else {
l = mid + 1
}
}
return l
}