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
tag: array, binary search, two pointers
method 1 sort
method 2 set
method 3 环检测算法(Floyd’s Tortoise and Hare)
这是链表环中的快慢指针迁移运用过来的算法,因为要找重复的数,并且不运用辅助的空间,那就是环检测算法。只是数组的环检测算法跟链表的环不一样,数组的环是由索引i和对应的值nums[i]构成的环, nums[i]作为下一步的i,因为有两个索引它们对应的值重复,所以构成了环
环检测算法的解释可看:https://blog.csdn.net/xyzxiaoxiong/article/details/78761940作了详细的解释
phase1 tortoise即第一次相遇点
phase2 因为在h点第一次相遇,而为什么b=F在链接中也解释的很清楚,虽然这个公式不是太准确,但可以由小及大
第一个循环就是hare一次走两步,tortoise一次走一步,那么在有环的情况下,他们迟早相遇,tortoise即为相遇点
第二个循环,令ptr1为头指针,令ptr2为相遇的几点,因为b=F那么,那么他们每次走一步,那么将在入口节点相遇
public int findDuplicate(int[] nums) {
// Find the intersection point of the two runners.
int tortoise = nums[0];
int hare = nums[0];
do {
tortoise = nums[tortoise];
hare = nums[nums[hare]];
} while (tortoise != hare);
// Find the "entrance" to the cycle.
int ptr1 = nums[0];
int ptr2 = tortoise;
while (ptr1 != ptr2) {
ptr1 = nums[ptr1];
ptr2 = nums[ptr2];
}
return ptr1;
}
method 4 Binary Search
使用鸽笼原理,当数组内的数<= mid的个数多余mid时,将search范围放在mid~high,
当个数小于等于mid时,将search范围放在low~mid,最后返回low/high(指的是索引)
巧妙的运用二分法
如n=10,mid=5,如果数组内小于等于5的个数多余5个,那么根据鸽笼原理,重复的数必在1~5内
public int findDuplicate2(int[] nums) {
int low = 1, high = nums.length - 1;
while (low < high) {
int mid = (low + high) / 2;
int count = 0;
for (int num : nums) {
if (num <= mid) count++;
}
if (count <= mid) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
Summary:
- 环检测算法构建环,找重复
- 二分法和鸽笼原理的结合