First Missing Positive 找到数组中缺失的最小正整数

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

对两篇高赞帖子的学习记录,下面是原文链接
链接1: https://leetcode.com/problems/first-missing-positive/discuss/767105/Short-C%2B%2B-O(n)-time-O(1)-space-oror-Steps-explained.
链接2: https://leetcode.com/problems/first-missing-positive/discuss/781724/C%2B%2B-simple-5-line-solution-O(n)-time-and-O(1)-space.


提示:以下是本篇文章正文内容,下面案例可供参考

一、原题

英文原题:Given an array of n(n>1)integers, please design an algorithm that is as efficient as possible in terms of time to find the smallest positive integer that does not appear in the array. For example, the smallest positive integer that does not appear in the array {-5, 2,3,6} is 1; the smallest positive integer that does not appear in the array {1,2,3} is 4。
(1)Please describe your algorithm in C or C++ language, and give comments on key codes
(2)Explain the time complexity and space complexity of your algorithm

中文描述:
对一个未排序的数组,找出缺失的最小正整数。
例如,对于数组[1,2,3]返回4;对于数组[-5, 2,3,6]返回1。
用C或C++对算法进行描述,并对关键代码进行注释;解释算法的时间复杂度和空间复杂度。

二、算法分析及代码

1.算法分析

题目所求的最小正整数是落在[1,n+1]中的,n是这个数组元素的数量,命名这个数组为nums,因为是最小正整数嘛,最大的情况是从1开始排[1,2,3…]。

首先先判断数组是否大于0或者是否为非正数,即nums[i]>n或者≤0,如果是,则这些数肯定跟我们要求的最小正整数无瓜,所以我们研究nums[i]∈(0,n]的数即可。

第二也是最核心的要点,判断这个数是否存放在和其对应的位置上,如一个数组[3,1,-4,7],第一个元素3 (nums[0]) 不在第三个位置( nums[nums[0]-1] )上,即nums[i]!=nums[nums[i]-1],那么则让它和第三个元素进行交换,变为[-4,1,3,7],遍历完整个数组后,记住,只对nums[i]∈(0,n]的数进行操作,最后变为[1,-4,3,7],这样,第一个位置号和元素值不相等的位置号就是缺失的最小正整数 。(注:位置号=数组编号+1)

2.代码

代码如下(示例一)该代码和算法分析完全一致:

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n=nums.size();
        for(int i=0 ; i<n ; i++)
        {
            while(nums[i]>0 and nums[i]<=n and nums[i]!=nums[nums[i]-1])
                swap(nums[i],nums[nums[i]-1]);
		//[3,1,-4,7]举例
		//i=0时,3 != nums[3-1],交换后数组变为[-4,1,3,7];
		//i=1时,1!=nums[1-1],交换后数组变为[1,-4,3,7];
		//i=2时,3==nums[3-1]
		//i=3时,7>n
        }
        for(int i=0 ; i<n ; i++) if(nums[i] != i+1) return i+1;
        return n+1;
    }
};

代码如下(示例二):
示例一是有交换的过程,该示例省了交换这一步,首先将nums[i] ≤ 0的数令为n+1,再对nums[i] <= n的元素进行操作,将该元素对应数组中相应位置的值 即 nums[nums[i] - 1] 进行取反。这种方法我觉得其实是和示例一的交换本质上类似,示例一是交换后,看哪个位置号首先和值不同,这个是取反后,看哪个位置元素首先为正,但这个就更简单了。

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int i = 0; i < n; i++) if (nums[i] <= 0) nums[i] = n + 1; //对≤0的数赋值n+1
        for (int i = 0; i < n; i++) if (abs(nums[i]) <= n && nums[abs(nums[i]) - 1] > 0) nums[abs(nums[i]) - 1] *= -1;	
        //[3,1,-4,7]举例,经过第一个for循环,数组变为[3,1,5,7]
        //nums[abs(nums[i]) - 1]或nums[nums[i] - 1]代表的是这个元素对应数组中相应位置的值
        //如nums[0]=3,nums[nums[i] - 1]=-4
        //经过第二个for循环,数组变为[-3,1,-5,7]
        //我觉得这里可以不用abs绝对值函数,因为经过第一个for,数组元素都为正了
        //所以第二个for循环我觉得可以改为 示例二改这样子
        for (int i = 0; i < n; i++) if (nums[i] > 0) return i + 1;
        return n + 1;
    }
};

代码如下(示例二改)(真的是很漂亮):

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

总结

第一次写CSDN,有什么问题欢迎大家交流指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值