这题用数组当哈希表,原地放回正数,怎么改成?
摘要:本题在线练习:LeetCode 41. 缺失的第一个正数 - 在线练习(免费 · 无需登录 · AI 辅助)(https:onefly.topzero2Leetcodeplaygr
本题在线练习:LeetCode 41. 缺失的第一个正数 - 在线练习(免费 · 无需登录 · AI 辅助)(https://onefly.top/zero2Leetcode/playground.html?id=41)
配套刷题网站 Zero2Leetcode —— 内置本地 OJ + AI 教练,零门槛开始刷 Hot 100。
题目概述
给定一个未排序整数数组 nums,找出其中缺失的最小正整数。
要求:时间 O(n),额外空间 O(1)。
这题的难点在于:既要线性时间,又不能用额外哈希集合。正确思路是“原地哈希”:把值 x 放回它应该在的位置 x-1。
核心思路:答案只可能在 [1, n+1]
数组长度为 n,如果 1..n 都存在,那么最小缺失正数就是 n+1。
所以只需要关心区间 [1, n] 内的数,其他(负数、0、>n)都可以忽略。
目标:让数组满足尽可能多的“值归位”:
如果数组里有数 x(1<=x<=n),就尝试把它放到下标 x-1 的位置上。
归位完成后,再从头扫一遍,找到第一个 nums[i] != i+1 的位置,答案就是 i+1。
代码实现(原地交换归位)
class Solution:
def firstMissingPositive(self, nums: list[int]) -> int:
n = len(nums)
i = 0
while i < n:
x = nums[i]
# x 应该放在 idx = x-1
if 1 <= x <= n and nums[x - 1] != x:
nums[i], nums[x - 1] = nums[x - 1], nums[i]
else:
i += 1
for i in range(n):
if nums[i] != i + 1:
return i + 1
return n + 1
逐行拆解:为什么要用 while 而不是 for
因为交换后 nums[i] 变成了一个新值,可能仍然需要继续归位。
用 while:
如果发生交换,不增加 i,继续处理当前位置
如果不需要交换,才 i += 1
这样能确保每个值最多被交换到位一次,整体仍是 O(n)。
手动模拟:nums = [3,4,-1,1]
n=4,只关心 1..4。
i=0,x=3 应放到 idx=2:交换 -> [-1,4,3,1]
i=0,x=-1 无视,i=1
i=1,x=4 应放到 idx=3:交换 -> [-1,1,3,4]
i=1,x=1 应放到 idx=0:交换 -> [1,-1,3,4]
i=1,x=-1 无视,继续
归位后从头扫:
i=0 是 1 对
i=1 不是 2,答案 = 2
复杂度分析
时间:O(n)(每个元素交换次数有限)
空间:O(1)
总结
缺失的第一个正数的关键思路是“原地哈希”:
只关心 [1, n]
把值 x 放到下标 x-1
再线性扫描找第一个不匹配的位置
把“数组当哈希表”这个技巧吃透,后面很多原地题(找缺失数、找重复数的变种)都会更有把握。
