算法1:最小未出现的正整数

算法:最小未出现的正整数

问题描述:给定一个未排序的数组,找出其中没有出现的最小正整数(num>=1)

示例1:
>   输入:[1,2,0]
>   输出:3
示例2:
>输入:[3,4,-1,1]
>输出:2
示例3:
>输入:[7,8,9,10]
>输出:1
说明:本题描述虽然十分简单,但是想要做到最好的效果并不容易想到,我们可以从时间复杂度和空间复杂度上面要求: 1.时间复杂度为O(n) 2.空间复杂度为O(1) 首先我们需要分析一个给定长度n的数组,所求的数最大为n+1,最小为1;所以我们可以得出几个结论:
1.当arr[i]>n的时候,arr[i]+1>n+1,必然不会是所求的结果,所以我们可以直接舍弃这个元素
2.当arr[i]<0的时候,arr[i]+1<1,必然不会是所求的结果,所以我们也可以直接舍弃这个元素

假设我们现在只考虑时间复杂度为O(n)的情况,那么我们可以如下考虑

可以定义一个临时的数组temp,大小为n,令他所有元素为0;遍历原数组arr,当arr[i]>0&&arr[i]<=n,temp[arr[i]]=1 。
最后我们可以得出temp数组下标最小的0元素的下标i就是我们所求的最>小未出现正整数i+1

class solution{
    public :
        int firstMissingPositive(vector<int>& nums){
            int size = noms.size();
            int *temp = new int[size];
            for(int i=0; i<size;i++){//初始化
                temp[I]=0;
            }
            for(int i=0; i<size;i++){//判断
                temp[i]=0;
                if(nums[i]>0&&nums[i]<=size){
                    temp[i]=1;
                }
            }
            for(int j =0;j<size;j++){//得出结果
                if(temp[j]==0)
                    return j+1;
            }
            return 0;
        }
}

【参考资料】

现在我们再加大难度,考虑时间复杂度为O(n),并且空间复杂度限制在O(1)的情况

在此之前,我们可以先考虑下面两种简化情况:

1.给定一个数组a,长度为n,除了a[0]以外,其他元素都有a[i]==i,请找出第一个大于0并且不在这个数组里面的正整数

解答:n+(a[0]==n);当a==NULL,return 1
注意:必须考虑只有一个元素a[0]的情况,和元素为空的情况。

2.给定一个数组,长度为n,存在K个元素使得a[i]<0或者a[i]>n,其他元素a[i]==i,请找出第一个大于0并且不在这个数组里面的正整数

情况1:当k==0,也就是类似于问题1,
情况2:当k!=0,扫描完一遍数组,当第一个出现i!=a[i]的时候,i就是答案:

if(n<=0)return 1;    //判断数组是否为空
for(int i=0;i<n;i++){//数组不为空,开始循环查找i!=a[i]
    if(I!=a[i]){
        return i;
    }
}
return n+(a[0]==n);//查找结束,回到问题1

经过上面两道小问题之后,我们可以发现原本的问题是可以转化到上面这两道题的

首先,我们遍历数组,将所有0 < a[i] < n 的元素都交换到对应的下标中,即a[i]==i.
然后,就转化到了问题2
代码如下

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int size = nums.size();
        if(size <=0) return 1;
/*巧妙之处在这里,看似双重循环,其实只遍历了一遍数组,因为在内层交换过后,存在一部分i==a[i],当外层遍历到该元素,就不会进入循环内,相当于只遍历了一遍数组。*/
        for(int i=0;i<size;i++){
            while(nums[i]>0&&nums[i]<size&&(i!=nums[i])){
                int t = nums[i];
                if(nums[t]==nums[i]) break;
                int tmp = nums[i];
                nums[i]=nums[t];
                nums[t] = tmp;
            }
        }

        for(int i =1;i<size;i++){
            if(i!=nums[i])return i;
        }

        return size+(nums[0]==(size));
    }
};

【参考资料】

由于我们数组下标是从0开始的,所以nums[0]是经常作为临界条件出现的,我们需要判断nums[0]是否等于数组长度的情况

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值