☰
力扣41缺失的第一个正数(哈希表法)
2026/10/8 14:28:30 网站建设 项目流程

41. 缺失的第一个正数 - 力扣(LeetCode)

为什么用哈希表:

哈希表是一个可以支持快速查找的数据结构:给定一个元素,我们可以在O(1)的时间查找该元素是否在哈希表中

实现参考思路:

将数组所有的数放入哈希表,随后从 1 开始依次枚举正整数,并判断其是否在哈希表中。

想清楚:对于一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N+1] 中。

Ⅰ、筛选

所以我们先把所有不可能是答案的:负数、0、先筛去(即放到答案范围之外,即N+1后面)

怎么筛?

0、负数一律变成N+1(第一轮筛选)eg.1、0 、5=>1、4、5

for (int i = 0; i < n; ++i) { if (nums[i] <= 0) { nums[i] = n + 1; } }

Ⅱ、标记

符合要求的数字前面的那一个数字取为负数,当作标记符号来用×

原理解:符合要求的数字前面那一个数字取负数标记 ❌

实际原理:拿当前读到的数字本身作为下标,数字-1得到目标位置,把这个目标位置的值标记成负数 ✅(当作标记符号)


num ∈ [1,n]:把nums[num-1]置负(打标记,表示 num 存在)

for (int i = 0; i < n; ++i) { int num = Math.abs(nums[i]);//① 取绝对值,防止已经被标记成负数 if (num <= n) { nums[num - 1] = -Math.abs(nums[num - 1]);//② } }

第二轮循环代码中两个取绝对值的位置分别有什么用:
①读数据时,消除前面循环(可能)留下的负标记,拿到原始数字

②打标记时,先消除目标位置已有的负号,再强制置负,避免重复数字反复翻转正负

Ⅲ、根据标记找答案

从左往右遍历数组,找第一个 >0 的位置,下标 i,答案就是 i+1

for (int i = 0; i < n; ++i) { if (nums[i] > 0) { return i + 1; } }

这不是找到的第一个出现的正数?本题目不是求第一个缺失的正数?

注意了这里找的是nums[i]> 0而不是< 0,是没有标注的位置,说明数字i+1从来没有在数组里出现过

否则(即从第1个到第n个都不符合)返回N+1
return n + 1;

完整代码回顾

class Solution { public int firstMissingPositive(int[] nums) { int n = nums.length; for (int i = 0; i < n; ++i) { if (nums[i] <= 0) { nums[i] = n + 1; } } for (int i = 0; i < n; ++i) { int num = Math.abs(nums[i]); if (num <= n) { nums[num - 1] = -Math.abs(nums[num - 1]); } } for (int i = 0; i < n; ++i) { if (nums[i] > 0) { return i + 1; } } return n + 1; } }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询