LeetCode--41.缺失的第一个正数

前言:暑假开始咯,可以好好更新了,可以好好期待一下哦

解题思路:

        1.获取信息:

                给定一个未排序的整数数组,要求找出没有出现的最小正数

                限制条件:时间复杂度为O(N),只能使用常数级别的额外空间

                提示:1 <= nums.length <= 105

       -pow(2,31) <= nums[i] <= pow(2,31) - 1

        2.分析题目:

                (我做了,发现题目中其实没有标明一些额外的信息,这些信息要你去做,然后碰壁之后,才会发现,所以人生就是一个碰壁然后不断学习的过程,在这里我就直接写出来了)

                额外信息:数组中会有重复的元素

                我一开始,看到这个限制条件,本来想像之前一样,出个反骨法的,但是如果无视只能使用常数级别的额外空间这个条件时,我想到会用一个较大的容器来装入每个数字,之后进行遍历,看看哪个最小的正整数的不在其中即可,但是由于数字最大可为INT_MAX,如果无视这个条件的话,分配这个大个空间,时间复杂度早就不堪重负了

                所以,本次题解没有喜闻乐道的反骨法(即,哈希表法),那就老老实实开始解题吧

                我把每种方法的思路放在了尝试编写代码环节里面,借着代码来帮助你理解,这里就不做过多的阐述了

        3.示例查验:

                示例2:提醒你,数组中还会出现负数和0

                示例1和示例3:留着试验自己的思路是否可行

        4.尝试编写代码:

                (1)动态规划:

                        思路:既然无序实在是难以下手,那么不如就把它排序一下

                                我们把它排序过后,从左往右开始遍历

                                由于要寻找未出现的最小正整数,所以,负数和0都跳过,即:舍去,不考虑

                                接下来就全是正整数了

                                此时无非就三种情况:

                                1.第一个正整数不为1,说明,最小的未出现的正整数为1

                                2.第一个正整数为1,且后续的正整数都是连续的,说明,未出现的正整数为该数组内最大的正整数加上1

                                3.第一个正整数为1,但后续的正整数不连续,说明,最小的正整数在这些正整数的中间(不包括第一个正整数和最后一个正整数)

以下是完整代码:

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        sort(nums.begin(),nums.end());//对数组进行从小到大的排序
        int size=nums.size();//求出数组的大小
        if(nums[size-1]<=0)return 1;//如果排序后的数组中最大的数小于1,则最小的未出现的正整数为1
        int pointer=0;//设立遍历的开头
        while(nums[pointer]<=0)pointer++;//跳过所有非正整数
        if(nums[pointer]!=1)return 1;//如果第一个正整数不为1,则返回1
        for(pointer;pointer<size-1;pointer++){//开始遍历
            if(nums[pointer+1]-nums[pointer]<=1)continue;//如果前一个正整数和后一个正整数等于或者两者相差1,则跳过
            else return nums[pointer]+1;//否则返回未出现的最小整数
        }
        return nums[pointer]+1;//返回数组中最大正整数加1
    }
};

                (2)分治法

                        思路:我们还是对它进行从小到大的排序

                        我们每次都将数组分为两部分,直到分成的小组中的数字为1或者2,这个时候,就可以轻而易举地得出,每个小组中未出现的最小正整数是多少了,接下来就对这些正整数进行分析即可

                        话语无力,还是代码比较有说服了,这次要使用递归

以下是完整代码

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        sort(nums.begin(),nums.end());//排序
        int size=nums.size();//求出数组的大小
        if(nums[size-1]<=0)return 1;//如果排序后的数组中最大的元素小于1
        int begin=0;//设立左指针
        while(nums[begin]<=0)begin++;//跳过非正整数,确保指针指向的是第一个正整数
        if(nums[begin]!=1)return 1;//如果第一个正整数不等于1,则返回1
        return reBack(nums,begin,size-1,size-1);//开始进入递归
    }
private:
    int reBack(vector<int>&nums,int l,int r,int border){
        if(r-l<=1){//如果分成的小组中的元素数目为1或者2
            if(nums[r]-nums[l]>1)return nums[l]+1;//如果两个元素相差大于1
            if(r==border&&nums[r]!=INT_MAX)return nums[r]+1;//如果右边的元素的指针等于数组的边界且,右边的元素不等于INT_MAX
            return 0;都不是,则返回0,说明两个元素相等或者相差为1或者只存在一个元素
        }
        int mid=(l+r)/2;//求出中间的指针
        int left=reBack(nums,l,mid,border);//求出左边区间的未出现的最小正整数
        int right=reBack(nums,mid+1,r,border);//求出右边区间的未出现的最小正整数
        if(left==0&&right==0){//如果两边返回值都为0
            if(nums[mid+1]-nums[mid]>1)return nums[mid]+1;
        }
        else if(left!=0&&right!=0)return left<right?left:right;//略
        else if(left!=0&&right==0)return left;//略
        else if(left==0&&right!=0){//略
            if(nums[mid+1]-nums[mid]>1)return nums[mid]+1;
            return right;
        }
        return 0;
    }
};

                (3)拟哈希表法 I

                        思路:我们在前面说了为什么本道题没有写反骨法对吧,那我们可不可以用另一种形式来模仿一下反骨法呢?

                        当然可以,哈希表法的本质是一个容器中存有连续的数,将一个数组中的所有元素放入其中,可以清晰地看见哪几个数并不连续

                        还是看代码吧,我就不阐述了,等明天早上,我补充一个图片吧,应该就比较好理解了

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int size=nums.size();
        for(int i=0;i<size;i++){
            if(nums[i]<=0)nums[i]=size+1;
        }
        for(int i=0;i<size;i++){
            int index=abs(nums[i]);
            if(index<=size){
                nums[index-1]=-abs(nums[index-1]);
            }
        }
        for(int i=0;i<size;i++){
            if(nums[i]>0)return i+1;
        }
        return size+1;
    }
};

                (4)拟哈希表法 II

                        思路:其实跟拟哈希表 I 方法差不多,所以,就看代码吧

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int size=nums.size();
        int i=0;
        while(i<size){
            if(nums[i] >= 1&&nums[i]<=size&&nums[i]!=nums[nums[i]-1]){
                swap(nums[i], nums[nums[i]-1]);
            }else{
                i++;
            }
        }
        for(int i=0;i<size;i++){
            if(nums[i]!=i+1)return i+1;
        }
        return size+1;
    }
};

本次题解就完事了,今天吃了一天的饭,很累了,但我还是坚持写完,有没有一点小小的感动

还是提一下,纸上得来终觉浅,绝知此事要躬行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值