题目:
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的整数
- 显然,这个数组中包含重复的数字
- 假设重复的数字只有1个,但重复的次数不定,请找出这个重复的数字
- 必须在O(n^2)的时间复杂度以及O(1)的空间复杂度下完成
- 不能修改原数组的内容
题解1(O(n^2))
class Solution {
public:
int findDuplicate(vector<int>& nums)
{
int n = nums.size();
for(int i=0 ;i < n; i++)
{
for(int j = i+1 ;j <n;j++)
{
if(nums[i]==nums[j])
return nums[i];
}
}
}
};
解题思路1:
这是一种很直接的思路。将数组中的元素两两对比,一旦发现有相等的元素,就把这个相等的元素输出出来。但这种解法的时间复杂度为O(N^2),称不上是一种好的方法。
题解2(O(n))
在Solution中,我看到了时间复杂度为O(n)的思路,值得学习。
int findDuplicate3(vector<int>& nums)
{
if (nums.size() > 1)
{
int slow = nums[0];
int fast = nums[nums[0]];
while (slow != fast)
{
slow = nums[slow];
fast = nums[nums[fast]];
}
fast = 0;
while (fast != slow)
{
fast = nums[fast];
slow = nums[slow];
}
return slow;
}
return -1;
}
题解2思路
这个解法的关键在于将数组看成是一个静态的链表。数组中的元素代表链表下一个元素的下标(也就是next)。由于存在n+1个1到n的整数,有一个重复的数字,这就说明了链表中必然成环。
例如给定数组[2,3,3,1],元素的遍历过程是2->3->1->3->1->3,说明了有两个next(1和2)同时指向3,意味着3为重复数字。
至于怎么找到这个两个节点同时指向一个节点,随后成环的情况,可以用快慢指针的方法来解决:先定义一个每次走两步的快指针,再定义一个每次走一步的慢指针,使得慢指针追上快指针。这个时候,再让将快指针拨回0,两个指针同速而行,最后交于同一节点,这个节点就是答案。