Description
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.
Note
1. You must not modify the array (assume the array is read only).
2. You must use only constant, O(1) extra space.
3. Your runtime complexity should be less than O(n2).
4. There is only one duplicate number in the array, but it could be repeated more than once.
Solution 1(C++)
class Solution {
public:
int findDuplicate(vector<int>& nums) {
if (nums.size() > 1)
{
int slow = nums[0];
int fast = nums[nums[0]];
while (slow != fast)
{
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (fast != slow)
{
fast = nums[fast];
slow = nums[slow];
}
return slow;
}
return -1;
}
};
后续更新
其他类似的题目可参考:
算法分析
这道题,其实很重要,LeetCode-141. Linked List Cycle,这道题其实告诉了我数列,array与链表之间完全是可以相互转换的。
当然,对数列的值有所要求,那就是数列的值是可以转换为索引的。当完成这一步之后,数列就可以转换为链表了。那就是将值转换为索引,然后由此可以访问下一个元素。
那么,成功将数列转换为链表之后,我们就可以换个角度看问题了,所谓数列中有重复元素,其实就是链表存在环。所以也可以使用“龟兔”赛跑的方法来判断是否存在环。
那么第一部分很明显,fast与slow是按照不同的速度遍历链表的,由于题目中的数组肯定存在闭环,所以,fast与slow一定会相遇。而且相遇在环中。但是,不是说在环中就意味着相遇的地方就是重复的元素,其实重复的元素应该是环的入口。因为环开始和结束的地方是同一个,这同一个地方就是要找到。
所以第二部分就是让fast从头开始走,slow保持原来的位置不变。二者按相同步长走,直到二者相遇,那么相遇的地方就是环的起点。这个是可以证明的。
简单的逻辑就是,假设环起点与链表起点距离为a,fast与slow相遇的点与环起点距离为c,环长度为b,那么可以证明:
a+c = Nb;
就是a+c是b的常数倍N,那么这时fast重新从起点出发,slow还是在c处,slow比fast多a+c,但是slow在环内,所以二者必然在经过一定时间(与N有关)后在起点相遇。
程序分析
略。