• 力扣每日一题41:缺失的第一个正数


    题目描述:

    给你一个未排序的整数数组 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

    通过次数

    325.7K

    提交次数

    749K

    通过率

    43.5%

    思路和题解:

    数组长度为n,则确实的第一个正数只能在[1,n+1]的闭区间

    思路一:暴力搜索。时间O(n^2),空间O(1),不符合要求

    依次判断[1,n]在不在数组里,如果不在就返回那个不在的数,如果都在就返回n+1。代码。

    1. //暴力循环
    2. class Solution {
    3. public:
    4. int firstMissingPositive(vector<int>& nums) {
    5. int n=nums.size();
    6. for(int i=1;i<=n;i++)
    7. {
    8. bool flag=false;
    9. for(int j=0;j<n;j++)
    10. {
    11. if(nums[j]==i)
    12. {flag=true;break;}
    13. }
    14. if(!flag) return i;
    15. }
    16. return n+1;
    17. }
    18. };

    思路二:普通的哈希表。时间O(n),空间O(n),不符合要求。

    用一个长度为n的数组来标记[1,n]有没有出现过。

    1. //普通哈希表
    2. class Solution {
    3. public:
    4. int firstMissingPositive(vector<int>& nums) {
    5. int n=nums.size();
    6. vector<bool> hash(n,false);
    7. for(int i=0;i<n;i++)
    8. {//出现了就标记为真
    9. if(nums[i]>0&&nums[i]<=n)
    10. hash[nums[i]-1]=true;
    11. }
    12. for(int i=0;i<n;i++)
    13. {
    14. if(hash[i]==false) return i+1;
    15. }
    16. return n+1;
    17. }
    18. };

    思路三:原地哈希表。时间O(n),空间O(1)

    思路二是我们能想到的比较好的办法了,但是空间复杂度还是不能达到要求,那我们怎么来优化这个空间复杂度O(n)呢?要知道,只用O(n)的时间复杂度,也就是只用一层的循环,要找出缺失的第一个正数的话,不用其他空间来存储正数存在的状态时不可能的。既然必须要用空间来存储一些状态,又只能额外使用常数的空间,那我们只好拿给定的数组nums作为存储状态的空间。也就是说用原数组nums作为哈希表。

    问题是怎么标记一个正数是否出现的状态。对于num<=0&&num>n的数,num在[1,n]之外无论怎么变化,都不会改变答案。那就干脆先把数组里所有<=0的数先变成n+1,之后再遍历数组,把每个[1,n]内的数num对应下标处都改为负数。最后再遍历一遍数组,对应元素不为负就说明这个数对应的位置是第一个缺失的正数。

    1. class Solution {
    2. public:
    3. int firstMissingPositive(vector<int>& nums) {//原地哈希表
    4. //第一个缺失的数只能出现在[1,n+1]的闭区间里
    5. int n=nums.size();
    6. for(int i=0;i<n;i++)
    7. {//若出现负数或零或大于n的数,那第一个确实的数就在[1,n]
    8. if(nums[i]<=0) nums[i]=n+1;
    9. }
    10. for(int i=0;i<n;i++)
    11. {//将[num-1]标记为负,表示正数num没有缺失,num>n时不用管
    12. int num=abs(nums[i]);
    13. if(num<=n)
    14. {
    15. nums[num-1]=-abs(nums[num-1]);
    16. }
    17. }
    18. for(int i=0;i<n;i++)
    19. {
    20. if(nums[i]>0) return i+1;
    21. }
    22. return n+1;
    23. }
    24. };

  • 相关阅读:
    [网鼎杯 2020 青龙组]AreUSerialz
    K8S常用命令
    TypeScript项目配置
    android应用间相互调用
    C++智能指针
    金九银十招聘季, APP测试面试题助你拿高薪Offer
    2024年2月最新微信域名检测拦截接口源码
    【C++】二叉树
    探索Terraform实践:优化基础设施管理
    第20篇 Vue命令简介
  • 原文地址:https://blog.csdn.net/m0_73441691/article/details/133873074