leetcode-287. Find the Duplicate Number

287Find 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:

  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.

题意:

给定一个数组,数组包含n+1个数,数的取值范围是1到n。其中数组中一定存在重复的数,求出这个重复的数。

思路:

本来是没什么难度的,但是要求的是不能修改数组,且空间复杂度为O(1)。

这里用到的方法叫:

 Floyd's Tortoise and Hare (Cycle Detection) 
先推荐一篇我看的讲解,我认为讲的还是比较清楚的: http://blog.csdn.net/monkeyduck/article/details/50439840
一下为从原博中转载的,复制到这只是为了方便下面的解释,还是要感谢原作者。如果有不妥,随时删。
-------------------------------------------------------------------------------------------------------------------------------

基本思想是将数组抽象为一条线和一个圆环,因为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处相遇!

图1


----------------------------------------------------------------------------------------------------------------------------------
这里我觉得他可能没说清的地方就是:
  • 关于那个怎么形成一条直线的,和一个圆的
  • 还有就是在后面的计算快指针和慢指针走过的距离中,a,c,x具体的表示是什么?

1.关于一条直线和一个圆
我们举个例子:nums = [ 1, 4, 4, 2 , 3], 下面就是圆和直线的形成:

2. 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;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值