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:

  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.

链接: http://leetcode.com/problems/find-the-duplicate-number/

题解:

很有意思的一道题目。 一开始就想到了Brute Force, 自然是O(n2)的Complexity,不满足题意。 后来看了Discuss和其中的一些资料,发现可以像Linked List Cycle II一样,用快慢指针来解决。非常巧妙。据传说这道题费了knuth大约24小时才解决...未验证,不过很有意思。 也有O(nlogn)的binary search解法,也很巧妙。

Time Complexity - O(n), Space Complexity - O(1)

public class Solution {
    public int findDuplicate(int[] nums) {
        if(nums == null || nums.length < 2) {
            return -1;
        }
        
        int slow = nums[0], fast = nums[nums[0]];
        while(slow != fast) {
            slow = nums[slow];
            fast = nums[nums[fast]];
        }
        
        slow = 0;
        while(slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        
        return slow;
    }
}

 

二刷:

这道题是Cycle Detection的经典题目,方法和LinkedList Cycle II完全一样,也就是找环的起点。 题目给定有重复数字存在,所以我们先用快慢指针找环。找到环以后设置一个指针从头走,另外一个指针在环内走,最后碰到的地方就是环的起点。这里时间复杂度是O(n),空间复杂度是O(1)。为什么时间复杂度是O(n)呢? 这里主要分两部分,第一部分是两指针相遇的时间。第二部分是从头走到环起点的时间。第二部分我们很容易就能看出是O(n)。 第一部分我们主要是考虑环的周长λ,相遇时间应该是c * λ,即环周长的常数倍,因为λ < n,所以我们也可以理解为O(n),这里解释得并不严谨,还需要好好推算和证明。

Java:

Time Complexity - O(n), Space Complexity - O(1)

public class Solution {
    public int findDuplicate(int[] nums) {
        if (nums == null || nums.length < 2) return 0;
        int fast = nums[nums[0]];
        int slow = nums[0];
        
        while (fast != slow) {
            fast = nums[nums[fast]];
            slow = nums[slow];
        }
        
        fast = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        
        return fast;
    }
}

 

三刷:

使用跟二刷一样的方法。

这道题为什么说是找环的起点呢?因为我们使用快慢指针,两个指针在环内部相遇的时候,相遇时的fast和slow指向的元素相等,只能说明环存在,并不能说明这个元素就是duplicate。而在这个数组中环的起点才是不折不扣的duplicate。

Java:

public class Solution {
    public int findDuplicate(int[] nums) {
        if (nums == null || nums.length < 2) return -1;
        int slow = nums[0], fast = nums[nums[0]];
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[nums[fast]];
        }
        
        slow = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
}

 

 

Reference:

http://keithschwarz.com/interesting/code/?dir=find-duplicate

http://www.cnblogs.com/yrbbest/p/4438820.html

https://leetcode.com/discuss/61514/understood-solution-space-without-modifying-explanation

https://leetcode.com/discuss/60830/solutions-explanation-space-without-changing-input-array

https://leetcode.com/discuss/61086/java-time-and-space-solution-similar-find-loop-in-linkedlist

https://leetcode.com/discuss/60852/ac-c-code-with-o-n-time-and-o-1-space

https://leetcode.com/discuss/64637/java-o-1-space-using-binary-search

https://leetcode.com/discuss/62696/tortoise-%26-haire-cycle-detection-algorithm

https://leetcode.com/discuss/69766/share-my-solution-o-n-time-o-1-space-12-ms

https://leetcode.com/discuss/60990/o-n-time-o-1-space-using-floyds-loop-detection

https://leetcode.com/discuss/60878/a-java-solution-o-n-time-and-o-1-space

https://leetcode.com/discuss/68441/simple-c-code-with-o-1-space-and-o-nlogn-time-complexity

https://leetcode.com/discuss/61179/short-versions-binary-search-solution-nlogn-pointer-detection

 

posted @ 2015-12-12 03:55  YRB  阅读(1107)  评论(0编辑  收藏  举报