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; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理