Leetcode 41 缺失的第一个正数

一、问题描述

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

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

二、示例及约束

示例 1:
输入: nums = [1,2,0]
输出: 3
解释: 范围 [1,2] 中的数字都在数组中。

示例 2:
输入: nums = [3,4,-1,1]
输出: 2
解释: 1 在数组中,但 2 没有。

示例 3:
输入: nums = [7,8,9,11,12]
输出: 1
解释: 最小的正数 1 没有出现。

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

自用示例 5:
输入: nums = [0]
输出: 1

自用示例 6:
输入: nums = [-1,-2,-3]
输出: 1

自用示例 7:
输入: nums = [1,2,3]
输出: 4

提示:
● n == nums.length
● 1 <= n <= 1 0 5 10^5 105
● 1 <= nums[i] <= n

三、代码

废弃方法一:二重循环

//从1开始依次枚举正整数至 n+1,并遍历数组,判断其是否在数组中。
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int i = 1; i <= n + 1; i++) {
        //初始化置为false,当遍历匹配到时,置为ture
            bool found = false;
            for (int j = 0; j < n; j++) {
                if(nums[j] == i) {
                    found = true;
                    break;
                }
            }
            //返回标记false的值,即未匹配到的正整数
            if (!found) {
                return i;
            }
        }
        return 0;
    }
};

废弃方法二:哈希表

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        unordered_map<int, int> mp;
        int n = nums.size();
        //记录每个数出现的次数
        for (auto& num : nums) {
            mp[num]++;
        }
        //遍历1到n,进行匹配比较
        for (int i = 1; i <= n; i++) {
            int count = mp[i];
            /*如果键 i 不存在于 mp 中,那么 mp[i] 会被初始化为 int 的默认值,即 0。
            这是因为 unordered_map 通过其 operator[] 为不存在的键隐式地插入了一个默认构造的值。
            所以,即使键 i 没有被显式地添加到 mp 中,mp[i] 仍然可以安全地访问,并且会返回 0。*/
            //如果次数为0,说明为缺失的第一个正整数,将其返回
            if (mp[i] == 0) {
                return i;
            }
            /* count方法
            if (!mp.count(i)) {  
                return i;  
            } */  
            /* find方法
            if (mp.find(i) == mp.end()) {  
        		return i;  
    		} */   
        }
        return n + 1;
    }
};

方法一:置换

//将范围正确的数,即[1, n]的数x放置到对应的下标位置,即x - 1
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int i = 0; i < n; i++) {
        //若元素范围在[1, n]中,且未被置换到相应位置,进行交换
            while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) {
                swap(nums[nums[i] - 1], nums[i]);
            }
        }
        //如果匹配不相等,则该位置所代表的数缺失,否则说明缺失n + 1
        for (int i = 0; i < n; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        return n + 1;
    }
};

方法二:负号标记

//将范围不正确的数,即非正数置为n + 1,将范围正确的数置为负,然后遍历判断是否为负,如果为负,代表这个数已存在,若为正,则代表找到了缺失的数,否则返回n + 1
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        for (int& num : nums) {
            if (num <= 0) {
                num = n + 1;
            }
        }
        for (int i = 0; i < n; ++i) {
            int num = abs(nums[i]);
            if (num <= n) {
            //对绝对值取负,保证有重复的数时仍然是负号标记
                nums[num - 1] = -abs(nums[num - 1]);
            }
        }
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                return i + 1;
            }
        }
        return n + 1;
    }
};

四、总结

时间复杂度:
废弃方法一:O( n 2 n^2 n2),嵌套循环,由于nums.length范围很大,会超时。
废弃方法二:O(n),其中 n 是数组 nums 的长度。
方法一:O(n),其中 n 是数组 nums 的长度。
方法二:O(n),其中 n 是数组 nums 的长度。
空间复杂度:
废弃方法一:O(1),没有额外空间。
废弃方法二:O(n),创建了一个n大小的哈希表。
方法一:O(1),没有额外空间。
方法二:O(1),没有额外空间。

废弃方法时间复杂度空间复杂度
废弃方法一O( n 2 n^2 n2)O(1)
废弃方法二O( n n n)O(n)
方法一O( n n n)O(1)
方法二O( n n n)O(1)
  • 14
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值