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.
链接: 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