[每日一题] leetcode 41. 缺失的第一个正数

123 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

41. 缺失的第一个正数

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

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。请你实现时间复杂度为 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
-2^31 <= nums[i] <= 2^31 - 1
思路

首先,题目要求的是最小的未出现的正整数,就相当于求一个 mex(nums)的东西嘛

那么,我们这个数据范围给的是 2312312^{-31} - 2^{31},那么,负数和零都是干扰项嘛!

根本不干涉我们的行动,在我们眼里面,和正无穷大没有任何区别

首先,我们将所以的负数给处理为一个远超过本题范围的"魔数"

其次,我们再来关心本体所存在的问题,找到最小的那个数。

这个题有点意思,和我前面写过的一道题类似,用来哈希的思想

前面那道题在这里

有兴趣可以去看那道题,更详细

这里简单介绍一下这种思想:

我当前这个数,若是在 [1,n][1, n] 的范围内,那么,我们可以把当前这个数交换道对于位置上去

什么意思呢?

形如这种: 原来是: x y x 2 x xx \ y \ x \ 2 \ x \ x ,现在变成 x 2 x y x xx \ 2 \ x \ y \ x \ x

实现了对换操作,每一次,都会交换到对应的元素上去一个元素,即总交换次数不超过 n/2\lceil n / 2 \rceil 次

因为每次交换完至少会有一个位置被安排上自己的数,然后下次就是另外一个数安排到对应位置上

最后,我们就可以清楚的知道了 在 [1, n] 中到底差哪个数了!

什么?你问大于 n 的数如何处理

需要处理么?

补充,若是[1, n] 都出现过,那么必定是 n + 1

代码
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        const int INF = 0x3f3f3f3f;
        for_each(begin(nums), end(nums), [&](auto& a) {
            if (a <= 0) a = INF;
        });
        auto compare = [&](int x) { 
            return x >= 1 && x <= n;
        };
        for (int i = 1; i <= n; i ++) {
            while (compare(nums[i-1]) && nums[i-1] != nums[nums[i-1]-1])
                swap(nums[i-1], nums[nums[i-1]-1]);
        }
        for (int i = 1; i <= n; i ++)
            if (nums[i-1] != i) return i;
        return n+1;
    }
};