LeetCode-287. Find the Duplicate Number

来源:互联网 发布:瓷砖一开二加工费算法 编辑:程序博客网 时间:2024/05/01 22:04

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.

方法一:暴力搜索

题目中说明有且仅有一个重复数字,那么我们可以从前往后一个一个比较,只要找到了相同的数字就说明那个是重复的,返回结果。
时间复杂度:O(n^2)
空间复杂度:O(1)
时间复杂度过大,不满足题意,但测试可以通过。
这里写图片描述

class Solution {    public int findDuplicate(int[] nums) {        int duplicate=nums[0];        for(int i=0;i<nums.length;++i)        {            for(int j=i+1;j<nums.length;++j)            {                if(nums[i]==nums[j])                {                    duplicate=nums[i];                    break;                }            }        }        return duplicate;    }}

方法二:排序查找

先将所有数字排序,排序后重复的数肯定就在一起,只需要遍历一次数组就能找到。
时间复杂度:O(nlgn)
空间复杂度:O(1)
因为经过了排序,所以时间复杂度还是不满足题意,测试可以通过。
这里写图片描述

class Solution {    public int findDuplicate(int[] nums) {        int duplicate=nums[0];        Arrays.sort(nums);        for(int i=1;i<nums.length;++i)        {            if(nums[i]==nums[i-1])            {                duplicate=nums[i];                break;            }        }        return duplicate;    }}

方法三:利用额外空间

使用Map集合来保存每个数出现的次数,如果有数字重复出现,则返回该数字。后来看了官网中的推荐解答,里面用的是Set这个集合,比Map简单不少。
时间复杂度:O(n)
空间复杂度:O(n)
因为用到了额外空间,所以空间复杂度不满足题意,测试可以通过。
这里写图片描述

class Solution {    public int findDuplicate(int[] nums) {        int duplicate=nums[0];        Map<Integer,Integer> numsMap=new HashMap<>();        for(int num:nums)        {            if(!numsMap.containsKey(num))                numsMap.put(num,1);            else            {                int newCount=numsMap.get(num);                newCount++;                numsMap.put(num,newCount);            }                        }        for(int num:nums)        {            if(numsMap.get(num)>1)            {                duplicate=num;                break;            }        }        return duplicate;    }}

方法四:

上面三个不满足题意的方法都是我想到的,但是我实在没想出怎样在满足题目要求的前提下解决此题,后面看了推荐解答,发现实在太巧妙了,利用寻找环的起始点这一模型来解决。
这种方法之所以可行是因为

由于数组的n + 1个元素范围从1到n,我们可以将数组考虑成一个从集合{1, 2, …, n}到其本身的函数f。这个函数的定义为f(i) = A[i]。基于这个设定,重复元素对应于一对下标i != j满足 f(i) = f(j)。我们的任务就变成了寻找一对(i, j)。一旦我们找到这个值对,只需通过f(i) = A[i]即可获得重复元素。

更具体的解释说明请看
英文原版
中文翻译版
时间复杂度:O(n)
空间复杂度:O(1)

class Solution {    public int findDuplicate(int[] nums) {        int fast=0;        int slow=0;        while(true)        {            slow=nums[slow];            fast=nums[nums[fast]];            if(slow==fast)                break;        }        int duplicate=0;        while(true)        {            duplicate=nums[duplicate];            slow=nums[slow];            if(duplicate==slow)                break;        }        return duplicate;    }}
原创粉丝点击