当前位置: 首页 > news >正文

hot100 缺失的第一个整数(41)

本题采用原地哈希(桶排序/基数排序思想)算法解决“缺失的第一个正数”问题。其核心本质是利用数组的索引下标作为天然的哈希表键值,通过不断的置换操作将符合范围的正整数强制归位到对应的物理位置。当前源码实现了在不占用额外内存空间的前提下进行数据的就位,最终走向是通过第二次线性扫描首个未就位的元素索引来精确锁定目标缺失值。

一、 问题本质与数据模型

对于长度为 n 的整数数组 nums,我们需要寻找没有出现的最小正整数。在处理该问题时,首先需要通过数学归纳确立结果的物理边界:

  • 最理想情况:如果数组包含从 1 到 n 的所有正整数[1, 2, 3, ..., n],那么缺失的第一个正整数必然为n + 1

  • 非理想情况:如果数组中存在小于等于 0 的数、大于 n 的数、或是重复的数,根据抽屉原理(鸽巢原理),缺失的第一个正整数必然落在[1, n]的有效闭区间内。

由此可得,最终的答案必然位于[1, n + 1]之间

这一数学边界直接决定了我们的数据模型:我们完全不需要理会小于等于 0 或大于 n 的数字,只需要聚焦于满足1 <= nums[i] <= n范围内的正整数,并设法验证它们是否全部就位。

在不被允许开辟额外哈希表的前提下,算法将原数组自身视为一个哈希表。对于任意满足范围的数值x,它在哈希表中的标准归宿就是数组的x - 1下标位置。即算法最终的目标是让数组尽可能满足:

nums[i] == i + 1

二、 算法演进对比

在解决动态正整数连续性判定问题时,原地哈希置换法在时空资源的利用效率上达成了最优解:

解法名称时间复杂度空间复杂度核心原理物理缺陷 / 瓶颈
标准双重循环排序O(n log n)O(1) 或 O(n)先对全数组进行快速排序或归并排序,随后线性扫描查找断层时间开销受限于排序上限,无法达到线性时间要求
辅助哈希集合去重O(n)O(n)将所有数字存入 HashSet,随后从 1 开始依次在集合中查询是否存在引入了与原数据等长的额外内存空间开销,违反常数空间约束
原地哈希置换(当前解法)O(n)O(1)利用数组下标作为哈希地址,通过不断交换元素让正确的数据归位需要在原数组内部进行直接的数据改写与位置置换

三、 原地哈希置换的核心控制逻辑

当前源码的卓越性在于通过一个内嵌的while循环实现了无额外空间的“数据自动归位”。其核心判定条件由三部分组成:

while (nums[i] >= 1 && nums[i] <= n && nums[nums[i] - 1] != nums[i])

1. 数值合法性过滤:nums[i] >= 1 && nums[i] <= n

只有当前元素位于[1, n]区间内时,它才拥有在数组中被归位的资格。任何负数、0 以及超出数组长度的大整数都无法匹配任何合法的数组下标,直接跳过。

2. 目标冲突判定:nums[nums[i] - 1] != nums[i]

这是防止算法陷入死循环的核心防护网。

  • 设当前位置的数值为x = nums[i],它本应该待的地方是目标索引j = x - 1

  • 只有当目标位置上的数值nums[j]还不等于x时(即nums[nums[i] - 1] != nums[i]),才需要执行交换。

  • 逻辑证明:如果满足nums[j] == x,说明该数字在目标位置上已经存在(遇到了重复元素)。此时如果继续交换,当前位置的值不会发生改变,while循环将永远无法退出。

3. 为什么必须使用while而不是if

当我们将nums[i]交换到它应该去的目的地nums[j]后,原本待在nums[j]的那个未知元素被换到了当前位置i。这个换过来的新元素同样可能是个合法的、需要归位的数字。因此必须使用while循环不断对当前位置i上的新元素进行重复判定与置换,直到换过来的元素是一个非法值或是一个已经正确就位的元素为止。

四、 算法执行状态机步进示例

以输入数据nums = [3, 4, -1, 1]为例(此时数组长度n = 4),外层循环变量i推进时的内部置换状态演进过程如下表所示:

步骤外层索引 i当前元素 nums[i]满足 while 条件与置换过程数组内部实时元素状态物理意义说明
初始---[3, 4, -1, 1]原始无序状态
103

满足。目标索引j = 3-1 = 2

nums[2](-1) 互换。

[-1, 4, 3, 1]数字 3 成功归位到下标 2
20-1-1 < 1,不满足条件,跳出 while。[-1, 4, 3, 1]当前位置为无效值,指针右移
314

满足。目标索引j = 4-1 = 3

nums[3](1) 互换。

[-1, 1, 3, 4]数字 4 成功归位到下标 3
411

满足。目标索引j = 1-1 = 0

nums[0](-1) 互换。

[1, -1, 3, 4]数字 1 成功归位到下标 0
51-1-1 < 1,不满足条件,跳出 while。[1, -1, 3, 4]当前位置为无效值,指针右移
623nums[2] == 2+1,已正确就位,跳过。[1, -1, 3, 4]指针右移
734nums[3] == 3+1,已正确就位,跳过。[1, -1, 3, 4]第一轮置换完全结束
扫描从 0 到 3-检查到nums[1] = -1 != 2触发return i + 1输出结果:2

五、源码实现

class Solution { public int firstMissingPositive(int[] nums) { // 边界安全检查 if (nums == null || nums.length == 0) { return 1; } int n = nums.length; // 步骤 1:原地哈希置换,尝试将每个满足 [1, n] 范围的数字 x 放到对应的下标 x - 1 上 for (int i = 0; i < n; i++) { // 使用 while 循环,持续对换到当前位置 i 的新元素进行就位处理 // 条件包含:数值在合法区间内,且目标位置上的数值与当前数值不相等(防重复死循环) while (nums[i] >= 1 && nums[i] <= n && nums[nums[i] - 1] != nums[i]) { // 计算目标归宿索引 int j = nums[i] - 1; // 进行原地元素对调 int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } } // 步骤 2:再次扫描调整后的数组,寻找第一个没有正确就位的物理位置 for (int i = 0; i < n; i++) { // 如果当前位置的值不等于 索引 + 1,说明该正整数缺失 if (nums[i] != i + 1) { return i + 1; } } // 步骤 3:如果数组中 [1, n] 的所有正整数都正确就位了,则缺失的必然是 n + 1 return n + 1; } }

六、 复杂度极限分析

1. 时间复杂度 O(n)

  • 精确摊还分析:虽然代码的结构上表现为for循环内部嵌套了一个while循环,但我们不能简单地将其评估为平方阶。从物理置换的本质来看,每一次成功的swap操作,都必然会将至少一个原本错位的数字送入到它长久正确的最终位置(即满足nums[j] == j + 1)。

  • 结论:一旦一个元素正确就位,它就绝不会再次被挪动。由于数组中总共只有 n 个元素,整个算法生命周期里发生的总交换次数绝对不会超过n - 1次。因此,while循环的平均摊还时间开销为常数阶 O(1),结合随后的第二次线性扫描,综合总时间复杂度稳定在 O(n)。

2. 空间复杂度 O(1)

  • 分析:算法所有的元素移位、调配与对调逻辑全部直接施加在传入的原始nums数组内存块上展开(原地算法)。执行期间,除独立声明了n,i,j,temp等有限个用于控制迭代和辅助对调的基础类型整型变量外,没有申请任何与输入规模相关的外部数据结构。

  • 结论:额外内存的消耗固定为常数阶,空间复杂度为严格的 O(1)。

http://www.jsqmd.com/news/1108561/

相关文章:

  • Linux 用户与权限(rwx)详解
  • MQ 选型最难的不是比吞吐,而是先判断你要的是事件日志、任务队列,还是业务消息
  • 多智能体角色一致性压力测试:基于M2.7的西游架构实践
  • Linux 【01- ping命令超详细教程】
  • codex多agent协作新手项目落地实践
  • 直流电机静音控制方案:TB9051FTG与PIC32MX764F128L应用
  • 春雨行动赋能,ChatiSS寒热辨证软件冲刺国内中医AI三类器械资质空白
  • 华为UVM技术分析:把GPU显存塞进Linux核心MM---GMEM实现简析
  • 抖音内容管理革命:如何用开源工具节省95%的下载时间
  • 基于改进YOLO11的天际线检测算法:复杂光照与恶劣天气适配实战
  • how to 梳理 this porject 结构 for quick knowing the 干什么的 which file
  • 如何免费解锁WeMod Pro功能?Wand-Enhancer完整指南
  • 智能体认知架构中的长期记忆与聊天摘要记忆管理系统研究报告
  • 原神帧率解锁工具:打破60帧限制,开启丝滑游戏体验
  • CaseViewer 2.4下载安装教程(附安装包)2026最新版(CaseViewer 2.4)
  • 手机号查QQ号终极指南:3步实现快速精准查询
  • VMware虚拟机固定IP配置全攻略:5步实现永久生效,附实测Shell脚本与network-scripts深度调优
  • 收藏!程序员转行AI:轻松入门大模型应用开发,高薪就业不是梦!
  • 解决 Hermes 依赖缺失报错,桌面端本地 AI 智能体分步搭建指南
  • 7种字重思源黑体TTF:如何构建专业级免费商用字体
  • 5分钟实战Unity游戏汉化:XUnity.AutoTranslator完全使用指南
  • 如何通过OneMore插件将OneNote效率提升300%:从普通笔记工具到专业知识管理系统的蜕变
  • HsMod:55项功能扩展全方位重塑你的炉石传说游戏体验
  • AGV锂电池与RGV锂电池的区别?(2026版知识手册)
  • 科研图表不用熬!paperxie AI 科研绘图,网页端三步搞定全学科学术出图
  • Forget About ChatGPT:AI落地的三域分治与工程化实践
  • AI时代生存指南:小白程序员必备的收藏级学习攻略!
  • 揭秘靠谱桁架机械手供应商的5个隐藏指标:专利、检测设备与产学研合作意味着什么?
  • 实战指南:如何高效解锁中兴光猫工厂模式与永久Telnet权限
  • VMware虚拟机USB设备失联?3步诊断法+4个隐藏配置项,95%问题当场解决