• 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;                //运行到这,说明容器内的元素全部能够被标记,那么未出现的值,一定比最大元素还大
        }
    };


    优化

    由于关心的是最小正数,于是在预处理阶段,将负数以及数字0,换为了比nums长度大的数,在染色的循环中,及跳过被预处理的数,又跳过本身就大于nums长度的数。减少了循环内的判断次数。提高了部分性能。

    class Solution {
    public:
        int firstMissingPositive(vector<int>& nums) {
            int iSize = static_cast<int>(nums.size());
            //预处理
            for(auto& elem : nums){
                if(elem <= 0){
                    elem = iSize + 1;
                }
            }
            //以elem - 1下标然nums染色
            int iIndex = 0;
            for(const auto& elem : nums){
                iIndex = std::abs(elem) - 1;
                if(iIndex >= iSize){        
                    continue;
                }
                if(nums[iIndex] < 0){
                    continue;
                }
                nums[iIndex] *= -1;
            }
            //寻找未染色位置
            for(int i = 0; i < iSize; i++){
                if(nums[i] > 0){
                    return i + 1;
                }
            }
            return iSize + 1;   
        }
    };


    枯了,还是吊车尾。。。。





    原创不易,转载请注明出处,谢谢
  • 相关阅读:
    zabbix监控系统客户端安装
    可以学习的博客地址
    Linux下Nagios的安装与配置
    ShopNC多用户商城标题去版权 后台去版权方法2.0版本
    解析crontab php自动运行的方法
    暑假周报告(第五周)
    暑假周报告(第四周)
    暑假周报告(第三周)
    暑假周报告(第二周)
    《大道至简》读后感
  • 原文地址:https://www.cnblogs.com/Keeping-Fit/p/14800423.html
Copyright © 2020-2023  润新知