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.
Example 1:
Input: [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2] Output: 3
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~n中间,假设只有一个重复的数字,这个数字可以重复很多次,求这个数字。
看Note,要求很高,最关键的要求就是不能更改数组,时间复杂度,空间复杂度都有要求。
首先我们降低一下难度,如果可以更改数组,根据上一篇笔记,有三种可行的方法:取反法,交换法,取余法。因为取余法比较容易理解和实现,而且使用范围特别广,不妨用取余法先来解决一下。代码如下:
1 class Solution { 2 public int findDuplicate(int[] nums) { 3 int n = nums.length; 4 for ( int i = 0 ; i < nums.length ; i ++ ){ 5 nums[ (nums[i] - 1) % n ] += n; 6 } 7 for ( int i = 0 ; i < nums.length ; i ++ ){ 8 nums[i] = (nums[i] - 1) / n ; 9 if ( nums[i] >= 2 ) return i+1; 10 } 11 return -1; 12 } 13 }
运行时间1ms,也是很快的算法了。但是问题就是改动了数组,因此下面就使用Floyd算法来做。
思路二:使用Floyd算法。
算法过程:
Floyd算法分为两个不同的阶段。第一个阶段是判断在链表中是否有环路,如果不存在就马上返回空,也就不存在第二阶段。第二个阶段就是找到环路的入口。
第一阶段:
初始化两个指针(快的兔子hare)和(慢的乌龟tortoise)。接下来,兔子hare和乌龟tortoise从同一个节点出发(头节点),乌龟tortoise每次走一个节点,兔子hare每次走两个节点。
如果他们在前进若干步后在同一个节点相遇,我们就返回这个节点,如果最终没有返回节点信息,而是返回空,则代表不存在环路。
第二阶段:
由于第一阶段确定了有环路,第二阶段就是找环的入口节点。接下来初始化两个个指针,ptr1:它指向头节点, ptr2:指向第一阶段找到的相遇节点。
然后将他们以一次移动一个节点的速度向前移动,直到他们再次相遇为止,并返回这个节点。
具体的算法证明在:印象笔记->leetcode->listnode中。
代码如下:
1 class Solution { 2 public int findDuplicate(int[] nums) { 3 int tortoise = nums[0]; //跑的慢的节点 4 int hare = nums[0]; //跑的快的节点 5 6 //第一个步骤,找到相遇点 7 //因为有1个重复的数组,所以肯定有“环 8 while ( true ){ 9 tortoise = nums[tortoise]; 10 hare = nums[nums[hare]]; 11 if ( hare == tortoise ) break; 12 } 13 14 //第二个步骤,找到环入口 15 int ptr1 = nums[0]; 16 int ptr2 = tortoise; 17 while ( ptr1 != ptr2 ){ 18 ptr1 = nums[ptr1]; 19 ptr2 = nums[ptr2]; 20 } 21 return ptr1; 22 } 23 }
运行时间0ms。其实这个算法可以作为Two Pointer的一个情况。
类似问题:[leetcode]141. Linked List Cycle
[leetcode]142. Linked List Cycle II