力扣(LeetCode)100题:41.缺失的第一个正数
41.缺失的第一个正数
我的题解:排序+遍历
class Solution:def firstMissingPositive(self, nums: List[int]) -> int:nums.sort()j=1for i in range(len(nums)-1):if nums[i]<=0 or nums[i]==nums[i+1]:continueif nums[i]==j:j+=1else:return jif nums[len(nums)-1]==j:j+=1else:return jreturn j
官方题解
一、哈希表
✅ 解法核心思想:原地标记法(利用数组下标作为“哈希表”)
我们将数组本身当作一个隐式的哈希表:
- 如果数字
x(1 ≤ x ≤ n)存在,则让nums[x - 1]变为负数(作为标记) - 最后遍历数组,第一个仍为正数的位置
i,说明i+1没有出现 → 即答案
🔍 逐行注释与解释
class Solution:def firstMissingPositive(self, nums: List[int]) -> int:n = len(nums)# 第一步:把所有非正数(≤0)替换为一个“无关”的大数(n+1)# 因为我们只关心 1 到 n 的正整数(答案一定在 [1, n+1] 中)for i in range(n):if nums[i] <= 0:nums[i] = n + 1# 第二步:遍历数组,对每个在 [1, n] 范围内的数 x,# 将 nums[x - 1] 标记为负数(表示 x 已出现)for i in range(n):num = abs(nums[i]) # 取绝对值,因为可能已被标记为负if num <= n: # 只处理 1 ~ n 的数nums[num - 1] = -abs(nums[num - 1]) # 标记位置 num-1 为负# 第三步:再次遍历,找第一个仍为正数的位置 i# 说明数字 i+1 没有出现过for i in range(n):if nums[i] > 0:return i + 1# 如果 1~n 都出现了,那么答案就是 n+1return n + 1
📌 为什么答案一定在 [1, n+1]?
- 数组长度为
n - 最理想情况:
nums = [1, 2, 3, ..., n]→ 缺失的是n+1 - 其他情况:至少有一个
1~n中的数缺失 → 答案 ∈[1, n] - 所以 答案 ∈ [1, n+1],无需考虑更大的数!
因此,我们可以安全地忽略所有 > n 或 ≤ 0 的数。
🧪 举例说明
示例 1:
nums = [3, 4, -1, 1]
n = 4
Step 1: 替换非正数
→ [3, 4, 5, 1] (-1 → 5)
Step 2: 标记出现的数
- i=0: num=3 → 标记 index=2 →
[3, 4, -5, 1] - i=1: num=4 → 标记 index=3 →
[3, 4, -5, -1] - i=2: num=5(>4)→ 忽略
- i=3: num=1 → 标记 index=0 →
[-3, 4, -5, -1]
Step 3: 找第一个正数
→ index=1 是正数(4)→ 返回 1+1 = 2 ✅
示例 2:
nums = [1, 2, 0]
n = 3
→ Step1: [1,2,4]
→ Step2: 标记 1→index0, 2→index1, 4忽略 → [-1,-2,4]
→ Step3: index2 为正 → 返回 3 ✅
示例 3:
nums = [1, 2, 3]
n = 3
→ 全部标记为负:[-1,-2,-3]
→ 没有正数 → 返回 4 ✅
二、置换
✅ 核心思想(原地置换 / Cyclic Sort)
数组长度为
n,则答案必定在[1, n+1]范围内。
若数字x(满足1 ≤ x ≤ n)存在,则应将其放到下标x - 1的位置上。
最终遍历数组,第一个不满足nums[i] == i + 1的位置,其i + 1即为缺失的最小正整数。
🧩 代码解析
class Solution:def firstMissingPositive(self, nums: List[int]) -> int:n = len(nums)# 将每个合法正整数(1~n)放到它“应该在”的位置:nums[x-1] = xfor i in range(n):while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:# 交换:把 nums[i] 放到正确位置,同时把原来那里的数换过来nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]# 找第一个“错位”的位置for i in range(n):if nums[i] != i + 1:return i + 1# 若 1~n 都在正确位置,则缺失的是 n+1return n + 1
