zoukankan      html  css  js  c++  java
  • 找出数组中重复的数字

    题目来源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;
        }
    };
  • 相关阅读:
    提交暂存更改时报 is outside repository 解决办法
    vue 路由跳转传参
    Unexpected token u in JSON at position 0 解决
    解决element table错位的问题
    使用docker制作Mysql镜像
    Linux系统性能排查
    分盘挂载
    Shell中的变量
    Shell流程控制
    Shell条件判断
  • 原文地址:https://www.cnblogs.com/mohari/p/13740272.html
Copyright © 2011-2022 走看看