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.

思路:在一个有n+1个元素的数组中包含的数字是在1-n的范围内。根据抽屉原理,至少有一个数字是会出现重复的。题目限定在数组中只有一个元素重复。题目相当于在n+1个空位上放上大小在1到n的数字。

算法的要求:

(1)不得修改数组。这样的话就不能通过给数组排序,然后找到相邻的数字相等的方式来找到出现两次的元素

(2)只能使用o(1)的空间。也就是不能通过map来存下每个元素对应的个数,最后找到那个个数等于二的元素这种方式

(3)要求算法的时间负责度小于o (n*n),则就不能通过针对每一个元素,遍历数组查看有没有重复的方式

解决方式:可以使用抽屉原理。设置start=0,end=nums.size()-1 ,则此时有n个位置,放置的元素在0~nums.size()-2之间。计算下标mid=(start+end)/2的大小是多少,然后统计在nums中小于mid的个数times。理论上如果不出现重复的话,在这个数组中小于mid的数字个数应该小于mid。此时如果统计的times>mid,则出现重复的数字的大小在0-mid之间,这个时候修改end=mid-1,计算数组的前一半。否则当mid>times的时候,则说明必有大于mid的数字出现了重复,则考虑数组的后一半即可,此时修改start=mid+1。由于题目要求必定含有重复的数字,就不考虑mid=times的情况了

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        //抽屉原理
        int left=0;
        int right=nums.size()-1;
        while(left<=right)
        {
            int mid=(left+right)/2;
            int times=0;
            for(int i=0;i<nums.size();i++)
                if(nums[i]<=mid)
                    times++;
            if(times>mid)
                right=mid-1;
            else
                left=mid+1;
        }
        return left;
    }
};

使用hash的方式在leetcode上也能过,代码如下

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        unordered_map<int,bool>res;
        int slo=INT_MIN;
        for(int i=0;i<nums.size();i++)
        {
            if(res.find(nums[i])!=res.end())
            {
                slo=nums[i];
                break;
            }
            else
                res[nums[i]]=true;
        }
        return slo;
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值