LeetCode 41题实战:用‘原地哈希’在O(n)时间内找出缺失的最小正整数(附C++/Python代码)

发布时间:2026/5/15 20:08:34

LeetCode 41题实战:用‘原地哈希’在O(n)时间内找出缺失的最小正整数(附C++/Python代码) LeetCode 41题深度解析原地哈希算法在缺失最小正整数问题中的精妙应用引言算法面试中原地哈希In-place Hashing是一种常被忽视却极其强大的技巧。当面对LeetCode第41题缺失的第一个正数时大多数求职者会陷入排序或哈希表的常规思路却忽略了题目对时间复杂度和空间复杂度的严苛要求。这道题之所以被标记为Hard不仅因为其思维难度更因为它完美展现了如何用基础操作解决复杂问题的艺术。本文将带你从问题本质出发逐步拆解原地哈希的核心思想揭示其在空间优化中的独特价值。不同于简单的代码实现我们会深入探讨算法设计背后的逻辑链条为什么常规方法失效原地哈希如何巧妙地利用现有空间如何处理负数、大数和重复值的边界情况通过完整的思路构建、代码实现和面试技巧你将掌握一种适用于多类约束性问题的通用解法。1. 问题分析与常规解法局限给定一个未排序的整数数组找出其中没有出现的最小正整数。题目要求时间复杂度O(n)且只能使用常数额外空间。让我们先看几个示例[1,2,0] → 3[3,4,-1,1] → 2[7,8,9,11,12] → 1直观解法及其问题暴力枚举法从1开始逐个检查是否存在于数组中。时间复杂度O(n²)空间O(1)def firstMissingPositive(nums): for i in range(1, len(nums)2): if i not in nums: return i排序法先排序再线性扫描。时间复杂度O(nlogn)空间取决于排序实现def firstMissingPositive(nums): nums.sort() res 1 for num in nums: if num res: res 1 return res哈希表法使用集合存储数字然后检查1到n1。时间O(n)空间O(n)def firstMissingPositive(nums): num_set set(nums) for i in range(1, len(nums)2): if i not in num_set: return i关键观察这些方法要么时间不达标要么空间不符合要求。我们需要一种能利用数组自身结构的解法。2. 原地哈希的核心思想原地哈希的精髓在于将数组索引本身作为哈希键。对于长度为n的数组缺失的最小正整数必然在[1, n1]范围内。我们可以重新排列数组使得数字i出现在索引i-1的位置即1在0位2在1位...。算法步骤遍历数组将每个数字x交换到x-1的位置忽略x ≤ 0或x n的情况它们不影响最小正整数的判断处理完成后第一个不满足nums[i] i1的位置即为答案C实现核心逻辑for(int i0; inums.size(); i){ while(nums[i]0 nums[i]nums.size() nums[nums[i]-1]!nums[i]){ swap(nums[i], nums[nums[i]-1]); } }为什么时间复杂度是O(n)每个数字最多被交换一次到正确位置尽管有嵌套循环但总操作次数与数组长度成线性关系。3. 边界条件与特殊处理3.1 处理重复元素当遇到重复数字时直接跳过避免无限循环while 0 nums[i] len(nums) and nums[nums[i]-1] ! nums[i]: nums[nums[i]-1], nums[i] nums[i], nums[nums[i]-1]3.2 大数和负数的影响数字n不影响最小正整数的判断缺失数≤n1数字≤0同样忽略因为它们不参与正整数序列Python完整实现def firstMissingPositive(nums): n len(nums) for i in range(n): while 1 nums[i] n and nums[nums[i]-1] ! nums[i]: nums[nums[i]-1], nums[i] nums[i], nums[nums[i]-1] for i in range(n): if nums[i] ! i1: return i1 return n13.3 置换环理论解析原地哈希本质上是将数组分解为多个置换环。每个环中的元素通过交换达到正确位置示例数组[3,4,-1,1] 置换过程 - 3应该到位置2 → 交换3和-1 → [-1,4,3,1] - -1跳过 - 4应该到位置3 → 交换4和1 → [-1,1,3,4] - 1应该到位置0 → 交换1和-1 → [1,-1,3,4] 最终检查发现位置1不是2返回24. 面试实战技巧与变体问题4.1 面试常见考察点复杂度分析如何证明时间复杂度是O(n)而非O(n²)边界测试空数组应返回1全负数数组应返回1包含重复元素的数组如[1,1]应返回2代码健壮性检查输入是否为null处理超大数组时的性能考虑4.2 面试官可能追问的问题如果允许O(n)空间你会如何优化解法如何修改算法使其同时找出所有缺失的正整数如果数组是只读的不可修改如何解决使用位图或二分法4.3 性能对比表格方法时间复杂度空间复杂度适用场景暴力枚举O(n²)O(1)小规模数据排序扫描O(nlogn)O(1)或O(n)无空间限制哈希集合O(n)O(n)时间敏感原地哈希O(n)O(1)严格空间限制5. 算法扩展与应用场景原地哈希不仅适用于本题还是一类空间敏感问题的通用解法模板寻找重复/缺失数字LeetCode 268, 287数组去重与重排将特定元素移动到指定位置受限环境下的计数问题当无法使用额外存储时进阶练习尝试用原地哈希解决LeetCode 442数组中重复的数据思考如何修改算法来找出前k个缺失的正整数研究Cyclic Sort模式的其他应用场景在实际工程中这种技巧可用于内存受限设备上的数据处理或需要极致优化的关键代码段。掌握它不仅能帮你通过算法面试更能培养出对空间复杂度的敏感意识——这是区分普通开发者和优秀工程师的重要标志之一。

相关新闻