41. 缺失的第一个正数

Posted 無雙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了41. 缺失的第一个正数相关的知识,希望对你有一定的参考价值。

toc

题目描述

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3
示例 2:

输入:nums = [3,4,-1,1]
输出:2
示例 3:

输入:nums = [7,8,9,11,12]
输出:1

提示:

1 <= nums.length <= 5 * 105
-231 <= nums[i] <= 231 - 1

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-missing-positive
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

此题在LeetCode上难度为困难,确实也挺难的,提交了几次才通过,通过的一次还时间空间双吊车尾。。。。。枯了。。。。
还是记录下,后面再优化。
思路在代码的注释上了,直接上代码吧。

代码

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        //总体放向,以nums内的元素做下标,染色下标指向的位置,再遍历nums,判断某位置是否被染色/标记来倒推元素是否存在
        //需要处理的问题:
        //问题1:题目求最小正数,最小正数为1,下标最低只能标记到1,显然,会漏掉0位置,因此以(元素 -1)做下标更为合理
        //问题2:由于nums取值范不再被限定,正负数均有,需要想办法区分,nums内某位置的值是被染色/标记,还是它本来就是个负数。由于需要寻找的是个正数,可以预处理一遍nums,想办法将负数去掉:
        //      1.直接去掉:将nums中的负数全部erase掉,但这样性能太差,循环erase时间复杂度也不满足O(n)
        //      2.将负数置0:元素为0,得到下标0 - 1,即-1,染色/标记毫无意义,直接跳过,所以置0不影响结果,因此选择置0
        int iSize = static_cast<int>(nums.size());
        for(auto& elem : nums){     //预处理
            if(elem < 0){
                elem = 0;
                continue;
            }
            if(elem > iSize){  //需要找的是最小正数,且下标为元素 - 1,所以大于nums长度的直接可以不用考虑了,也置0
                elem = 0;
                continue;
            }
        }
        //以elem - 1 做index,去染色/标记index所指位置,染色/标记方式为将该位置的值改为负数
        int iIndex = -1;
        for(const auto& elem : nums){
            if(0 == elem){                   //index = 0 - 1,即-1,标记-1位置毫无意义:1.会越界;2.求得是正数,0不是正数
                continue;
            }else if(-(iSize + 1) == elem){  //特殊标记位置,跳过
                continue;
            }

            iIndex = std::abs(elem) - 1;     //elem所处位置可能被染色,abs处理来得到原值     
            if(nums[iIndex] < 0){            //已经染色的位置,不用再次染色,避免染色失效
                continue;
            }
            if(0 == nums[iIndex]){          //>>>>>>>>>>iIndex位置的值为0,0无法使用乘以-1的方式染色,需要特别处理一下,赋值为-(iSize + 1)来染色<<<<<<<<<
                nums[iIndex] = -(iSize + 1);
                continue;
            }
            nums[iIndex] *= -1;             //染色/标记index位置
        }
        int iMaxElem = 0;                   //记录下容器内的最大值
        //从前往后,检查nums,查找未染色位置,首个未染色位置即为结果
        for(iIndex = 0; iIndex < iSize; iIndex++){
            if(nums[iIndex] >= 0){
                return iIndex + 1;          //index为元素 - 1,故所求元素应为index + 1
            }
            iMaxElem = iIndex + 1;
        }
        return iMaxElem + 1;                //运行到这,说明容器内的元素全部能够被标记,那么未出现的值,一定比最大元素还大
    }
};






以上是关于41. 缺失的第一个正数的主要内容,如果未能解决你的问题,请参考以下文章

41. 缺失的第一个正数

41. 缺失的第一个正数

41. 缺失的第一个正数(On)

LeetCode:缺失的第一个正数41

41. 缺失的第一个正数

[LeetCode 41.] 缺失的第一个正数