287. Find the Duplicate Number
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:
- 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.
题意:
给定一个数组,数组包含n+1个数,数的取值范围是1到n。其中数组中一定存在重复的数,求出这个重复的数。
思路:
本来是没什么难度的,但是要求的是不能修改数组,且空间复杂度为O(1)。
这里用到的方法叫:
Floyd's Tortoise and Hare (Cycle Detection)
基本思想是将数组抽象为一条线和一个圆环,因为1~n 之间有n+1个数,所以一定有重复数字出现,所以重复的数字即是圆环与线的交汇点。然后设置两个指针,一个快指针一次走两步,一个慢指针一次走一步。当两个指针第一次相遇时,令快指针回到原点(0)且也变成一次走一步,慢指针则继续前进,再次回合时即是线与圆环的交汇点。
看到这里是否感到似曾相识,没错!这就是Linked List Circle2的变形题目!参见我的另一博文点我跳转
看到这里有的童鞋可能已经晕了,为什么一定会汇合?为什么汇合点就是重复数字?不要着急,我们先把Linked list circle问题弄明白。如图1所示,两个指针同时从直线起点开始,假设在x处第一次汇合,xo之间距离为x,那么快指针走过的路程为a+c+x,慢指针走过的路程为a+x,所以a+c+x=2(a+x),所以c=a+x,也就是SO之间的距离等于xo,所以令快指针从起点开始一次一步,慢指针从x开始,同时前进,则必会在O处相遇!
- 关于那个怎么形成一条直线的,和一个圆的
- 还有就是在后面的计算快指针和慢指针走过的距离中,a,c,x具体的表示是什么?

public class Solution {
public int findDuplicate(int[] nums) {
int slow = nums[0];
int fast = nums[slow];
while (fast != slow){
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (fast != slow){
fast = nums[fast];
slow = nums[slow];
}
return fast;
}
}