41. 缺失的第一个正数

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

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

问题背景

在给定一个整数数组 nums 后,我们的任务是找出数组中 缺失的最小正整数。这道题的难点在于:必须 原地操作,即不使用额外的空间,并且 时间复杂度 需要保持在 O(n)

问题的核心是:如何在给定的数组中,找到不在 [1, n] 范围内的最小正整数,其中 n 是数组的大小。

解法思路

最直观的解法是通过 排序 数组,然后遍历查找缺失的最小正整数。然而,排序的时间复杂度是 O(n log n),而我们要求的是线性时间复杂度 O(n),因此排序不是最优解。

一种更加高效的解决方法是 通过原地交换将每个数字放到它该在的位置,然后遍历数组,寻找第一个缺失的正整数。我们利用数组本身的索引来为每个数字找到对应的位置,从而降低空间复杂度。

具体步骤

时间和空间复杂度

  1. 把每个数字放到它应该去的位置

    • 假设数字 x 应该放在索引 x - 1 位置上。通过交换,保证每个数字都尽量放在它应该在的位置。
    • 交换的条件是:nums[i]1n 之间,并且 nums[i] 不在它应该在的位置上。
  2. 遍历数组找缺失的最小正整数

    • 在交换完成后,遍历数组检查第一个不满足 nums[i] == i + 1 的位置。这个位置的索引对应的数字就是缺失的最小正整数。
  3. 如果数组包含所有 1n 的正整数,则缺失的最小正整数是 n + 1

    class Solution {
    public:
        int firstMissingPositive(vector<int>& nums) {//将数放在属于他的位置然后遍历一遍
            int n=nums.size();
            for(int i=0;i<nums.size();i++){
                while(0<nums[i]&&nums[i]<=n&&nums[i]!=nums[nums[i]-1]) swap(nums[i],nums[nums[i]-1]);//确保这个数是在1-n内的有效字符
            }
            for(int i=0;i<n;i++){
                if(i+1!=nums[i]) return i+1;
            }
            return n+1;
        }
    };

    代码解析

  4. 原地交换

    • 遍历数组,对于每个有效数字 nums[i],将它放到 nums[nums[i] - 1] 的位置上。这样,所有有效数字都会被放置到数组的正确位置。
    • 我们使用 while 循环来不断交换,直到当前数字在正确的位置上。
  5. 查找缺失的最小正整数

    • 在完成交换后,遍历数组,找到第一个位置 i,使得 nums[i] != i + 1。这个位置对应的数字 i + 1 就是缺失的最小正整数。
  6. 时间复杂度O(n),我们遍历数组进行交换操作,然后再遍历一次数组找缺失的正整数。每个元素最多交换一次,因此时间复杂度是线性的。

  7. 空间复杂度O(1),我们只用了常数空间来进行交换操作,没有使用额外的数据结构。

    • 返回结果

      • 如果数组中已经包含了所有的数字 1n,那么缺失的最小正整数就是 n + 1

        总结

        通过原地交换,将数字放到正确的位置,最终我们可以找到缺失的最小正整数。这种方法的时间复杂度是 O(n),空间复杂度是 O(1),非常高效。希望这个解法能够帮助你更好地理解和解决这类问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值