给定一个未排序的数组nums,每个包含n + 1个整数 整数介于1和n之间(含),证明至少有一个 必须存在重复的数字。假设只有一个副本 数字,找到重复的。
注意:
您不能修改数组(假设数组是只读的)。
您必须只使用常数,O(1)额外空格。
- 醇>
数组中只有一个重复的数字,但可以重复多次。
对于注释1,我们不能对数组进行排序,对于注释2,我们不能使用散列。我想我们可以在这里使用二进制搜索。
假设我们这个数组有重复的数字4:
[1, 4(was 2), 3, 4, 5, 6, 4(was 7), 8, 9, 4]
我们的想法是通过范围过滤器(如[7,9])查看数组,可能会出现2种情况:
案例1:范围包含重复元素,在这种情况下,我们可以在过滤器中找到的元素数量必须大于它应具有的元素数量。例如,如果我们看[3,4],我们会找到5个元素。如果没有重复,那么应该只有两个[3,4]。
这是正确的,因为其他一些元素可以重命名为该组,但不能重命名。在这种情况下,元素的预期数量是[3,4],但我们有一个额外的4(作为副本),然后两个4重命名,这就是为什么我们有5。
案例2:范围不包含重复元素,在这种情况下,我们在过滤器中可以找到的元素数量必须等于或小于元素数量。
以下是我的更新代码。我不确定哪一个在最后一行返回。虽然我测试过,发现低是正确的,但我仍然不知道原因。
public int findDuplicate(int[] nums) {
int low = 1, high = nums.length - 1;
while(low <= high){
int mid = low + (high - low) / 2;
int count = 0;
//count the number of elements in the filter [low,mid]
for(int i = 0; i < nums.length; i++){
if(nums[i] <= mid && nums[i]>=low){
count++;
}
}
if(count > mid-low+1){ //the duplicate would be in the left half
high = mid;
} else { //the duplicate would be in the right half
low = mid + 1;
}
}
return low; // Why we should return low here, not high?
}
答案 0 :(得分:2)
目前尚不清楚为什么您认为必须返回low
而不是high
。我怀疑你没有用许多不同类型的输入来测试它。对于输入1,1,2,高和低都将为0.无论您返回high
还是low
,答案都将是错误的。
换句话说:
您的算法的解释听起来是正确的。问题是,你没有实际实现你在那里解释的内容。您谈论计算范围内的元素,调整范围的下限和上限,但在实现中,您计算nums[I] <= mid
,因此只有上限更改(mid
),下限总是(隐式)0。这与您的解释不符。你没有正确实现你的想法。