找出数组中重复的数字

题目来源https://www.acwing.com/problem/content/description/14/

 思路:最直接的想法就是用map记录一下或者用set每次插入一个数判断一下长度有没有变化就好了。

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        map<int,int>vis;
        for(int i=0;i<nums.size();i++){
            if(nums[i]<0||nums[i]>=nums.size())return -1;
            vis[nums[i]]++;
        }
        for(int i=0;i<nums.size();i++){
            if(vis[nums[i]]>=2){
                return nums[i];
            }
        }
        return -1;
    }
};

但是map牺牲了大量空间换取时间,而set在空间和时间都不是最优的。

有更好的使用 O(1) 的额外空间的做法,由于数保证在0-n-1之内,则按如果没有出现重复,按升序排序每个数都可以和其数组下标对应。

利用这一点,我们可以将每个数和数组下标为这个数的数值进行交换,每次都可以至少将一个数放到正确的位置上,即使得num[i]=i;

如果有某个数和以其数为下标的数数值相同,且这个数的当前位置和该数值不对等,即说明出现了重复,在上一步无法进行交换。

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        for(int i=0;i<nums.size();i++){
            if(nums[i]<0||nums[i]>=nums.size())return -1;
        }
        for(int i=0;i<nums.size();i++){///swap最多n-1次,所以是o(n)
            while(nums[i]!=nums[nums[i]]){///每次都会使一个数放到合适位置,直到当前位置的数等于其下标为此数的数,此时如果该数和该位置不同则说明出现重复
                swap(nums[i],nums[nums[i]]);
            }
            if(nums[i]!=i){
                return nums[i];
            }
        }
        return -1;
    }
};

如果题目要求不能修改数组呢......

根据鸽巢原理,n+1只鸽子放到n个笼子里,至少有一个笼子有2只鸽子。

应用到这道题的话,由n个数的数据范围在为0-n-1,分治的思想可以把这个数据区间(取值范围)分为两段,如果该序列出现重复元素的话,一定会在其中一个区间出现数的个数大于该“数据区间”的长度,依次二分下去,最后得到的一个数就是重复的数字。

如果序列没有出现重复元素,那么在第一轮比较的时候就有左右数据区间的个数相同,即刚好占满n个元素。时间复杂度o(nlogn)

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        for(int i=0;i<nums.size();i++){
            if(nums[i]<0||nums[i]>=nums.size())return -1;
        }
        int l=0,r=nums.size()-1;
        while(l<r){
            int mid=(l+r)>>1;/// l mid mid+1 r
            int s=0;
            for(auto x:nums){
                s+= x>=l&&x<=mid;///在左区间的数
            }
            if(s>mid-l+1)r=mid;
            else if(s==nums.size()-s)return -1;
            else l=mid+1;
        }
        return r;
    }
};

 

posted @ 2020-09-27 16:24  mohari  阅读(210)  评论(0编辑  收藏  举报