41. 缺失的第一个正数
-
解题思路:整体思路就是,我们先假想,[0, n - 1]上,放满了1~n,所以,我们缺失的第一个正数就是n+1。也就是说,
i下标,放的数字是i+1。那么我们从左往右遍历的过程中,就尽量满足这种情况- 1️⃣如果
nums[i] == i + 1,直接跳过,啥都不管 - 2️⃣如果
nums[i] <= 0,那么,我们就「发货」到「无效区」。「无效区」是什么,我们可以理解是「当前状况下,没有必要处理的区域」,用R来表示,即[R, n - 1]是无效区。而R+1就是我们的答案。- 怎么理解,为什么要有这么个东西?
- 我们可以把nums划分成几个区域,
[0, i]就是我们处理过的区域,这部分的数据都是符合我们的预期,就是i下标,放i+1的数字。[i + 1, R - 1]就是我们还未处理过的数字。[R, n - 1]就是无效区。 - 为啥需要无效区?因为我们在
[i+1, R-1]这个区域时,如果遇到不符合我们的预期时,我们怎么处理这个数字?我们可以把这个数字扔到「无效区」,同时把R-1的数字放回到i位置来(和快排交换时,一样的操作),然后无效区范围扩大。
- 3️⃣如果
nums[nums[i] - 1] == nums[i],和2️⃣操作类似- 因为我现在想把
nums[i]放到下标为nums[i] - 1的位置,但是,如果这个位置的数已经是nums[i]了,那么就要放到「无效区」
- 因为我现在想把
- 4️⃣交换
i位置和nums[i] - 1位置的数
- 1️⃣如果
-
代码
class Solution { public: int firstMissingPositive(vector<int>& nums) { // 我们假想最「差」的情况,就是[0, n - 1]上分别是1~n,也就是说,nums[i]位置放置的数是i+1,那么,缺失的第一个正数就是n+1 int n = nums.size(); int R = n; // R + 1就是缺失的第一个正数 同时,不在我们预料中的数,放在[R, n - 1]中,称之为无效区 int L = -1; // [0, L]就是我们所说的nums[i]放置的数是i+1 int i = 0; while(i < R) { if (nums[i] == i + 1) { // 符合预期,不用管 i++; } else if (nums[i] <= 0) { // 不符合预期 「发货」到无效区 R--; nums[i] = nums[R]; // 为什么不把nums[i]放到无效区来?因为无效区的数我们直接不会处理了 } else { // nums[i] 我想放在nums[i]-1上 int index = nums[i] - 1; // 假设 nums[i] = 4,我想放到下标3中,但是如果下标3就是4呢?那么就多余了,所以「发货」到无效区 if (index >= R || nums[index] == nums[i]) { R--; nums[i] = nums[R]; } else { int tmp = nums[i]; nums[i] = nums[index]; nums[index] = tmp; } } } return R + 1; } };

浙公网安备 33010602011771号