LeetCode 287. Find the Duplicate Number

来源:互联网 发布:美加净防晒霜 知乎 编辑:程序博客网 时间:2024/06/05 04:01

  • 题目
  • 题意
  • 分析
  • 方法一 On2
  • 方法二 On

题目

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.

题意

给出一个数组nums,包含了n+1个取值为1~n整数,证明至少存在一个数重复。假设这里只有一个重复的数,把它找出来。
提示
1. 不能修改原数组(假设数组是只读的)
2. 只能使用常数O(1)额外的空间
3. 时间复杂度必须少于O(n^2)
4. 数组中至少会有一个重复的数,但是它可能重复多次。


分析

这道题不难,但是,题目对存储空间进行了严格的控制,并且要求时间复杂度为O(n^2)。
我一开始的想法比较简单,也能解决问题。也就是方法一,后面看到了另一种解法,感觉更高效,便也贴出来分析了,即方法二


方法一 O(n^2)

类似冒泡排序,用两个for循环,如果a[i] == a[j] ,则找到了重复的数。

其时间复杂度为O(n^2),空间复杂度为0。

int findDuplicate(vector<int>& nums) {    for (int i = 0; i<nums.size(); i++) {        for (int j = i + 1; j<nums.size(); j++)            if (nums[i] == nums[j])                return nums[i];    }}

LeetCode 上跑53个测试样例,耗时555ms 。


方法二 O(n)

看到了一个更好的解法。

首先。数组的值是在1~n,数组长度为n+1,这个是一个很特别的设定,因为,数组的值作为下标是合法的。

比如数组 [1,3,4,2,1]
1->3->2->4->1->3->2->4->1->…3->2->4->1->

因为有重复的数,所以一定存在闭环,而重复的数则是环的入口。

那么我们可以利用 Linked List Cycle的做法,用一个fast和一个slow,fast每次走两步,slow每次走一步,那么它们必定在闭环某个位置相遇。
然后,就需要找到闭环的入口了。使fast = 0,这次,fast和slow一样,每次走一步,当fast = slow的时候,它们就走到了入口

开始 : slow = 1 fast = 3
第一次 : slow = 3 fast = 4
第二次 : slow = 2 fast = 3
第三次 : slow = 4 fast = 4 相遇了

找闭环入口,即重复的数字
开始 : slow = 4 fast = 0
第一次 : slow = 1 fast = 1 找到入口

这样做的时间复杂度为O(n),空间复杂度度O(1)

int findDuplicate(vector<int>& nums) {    if (nums.size()<1)        return -1;    int slow = nums[0], fast = nums[nums[0]];    while (fast != slow) {        cout << fast << " " << slow << endl;        slow = nums[slow];        fast = nums[nums[fast]];    }    cout << "stop: " << fast << " " << slow << endl;    fast = 0;    while (fast != slow)    {        cout << fast << " " << slow << endl;        fast = nums[fast];        slow = nums[slow];    }    return slow;}

LeetCode 上跑53个测试样例,耗时12ms 。

0 0