【Hot 100 刷题计划】 LeetCode 41. 缺失的第一个正数 | C++ 原地哈希题解

LeetCode 41. 缺失的第一个正数 | C++ 哈希表基础解法

📌 题目描述

题目级别:困难 (Hard)

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

  • 示例 1:

    输入:nums = [1,2,0]

    输出:3

    解释:范围 [1,2] 中的数字都在数组中。

  • 示例 2:

    输入:nums = [3,4,-1,1]

    输出:2

    解释:1 在数组中,但 2 没有。


🚀 解法一:常规哈希表 (直觉解法,空间 O(N))

寻找"缺失的数字",最符合人类直觉的方法就是:把见过的数字都记在小本本上,然后从 1 开始挨个往上数,看看谁没被记过。

在代码实现中,这个"小本本"最合适的数据结构就是哈希集合(unordered_set)。

  1. 遍历原数组,把所有的正整数都扔进 unordered_set 中记录下来(自动去重且查找时间为 O(1)O(1)O(1))。
  2. 初始化一个目标值 target = 1,不断递增,去哈希表里查。
  3. 查不到的那个数字,就是缺失的第一个正数!

💻 C++ 代码实现

cpp 复制代码
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        // 使用哈希集合记录所有出现过的正整数
        unordered_set<int> seen;
        for (int num : nums) {
            if (num > 0) {
                seen.insert(num);
            }
        }

        // 从 1 开始逐个检查谁没出现过
        int target = 1;
        while (true) {
            // 如果在哈希表中找不到 target,说明这就是缺失的最小正数
            if (seen.find(target) == seen.end()) {
                return target;
            }
            target++;
        }
    }
};

🏆 解法二:原地哈希 / 循环排序 (面试满分终极解,空间 O(1))

题目给出了极其严苛的条件:时间 O(N)O(N)O(N) 且空间 O(1)O(1)O(1)。这意味着我们不能开辟新的哈希表,只能把原数组本身当作哈希表来用

对于一个长度为 NNN 的数组,它里面能装下的"连续正数"最多也就是 1, 2, 3... N

如果数组里装满了 1N,那缺失的正数就是 N + 1;如果不满,缺失的正数一定在 [1, N] 之间。

因此,我们可以制定一个规矩:数字 i 必须老老实实呆在索引 i - 1 的位置上(即数字 1 放在索引 0,数字 2 放在索引 1...)。这就好比"一个萝卜一个坑"。

操作步骤:

  1. 数字归位 :遍历数组,只要当前萝卜(数字)是个有效正数,且没呆在正确的坑位上,我们就把它交换到它该去的地方。换过来的新萝卜如果也不对,就继续换。
  2. 查岗核对:等所有萝卜都归位了,我们再从头巡查一遍。如果发现哪个坑里装的不是正确的萝卜,那个坑对应的数字就是缺失的!

💻 C++ 代码实现

cpp 复制代码
class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        
        // 第一阶段:将所有在 [1, n] 范围内的萝卜归位
        for (int i = 0; i < n; i++) {
            // 只要当前数字是有效正数,且不在正确的坑位上,就不断进行交换
            while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
                // 将 nums[i] 送回到属于它的索引位置 (nums[i] - 1)
                swap(nums[i], nums[nums[i] - 1]);
            }
        }

        // 第二阶段:查岗,寻找第一个坑位不对的数字
        for (int i = 0; i < n; i++) {
            // 索引 i 应该对应数字 i + 1
            if (nums[i] != i + 1) {
                return i + 1; // 找到了缺失的最小正数
            }
        }
        
        // 如果 1 到 n 都整整齐齐排好了,那缺失的就是 n + 1
        return n + 1;
    }
};
相关推荐
十五年专注C++开发2 小时前
达梦数据库在Linux备份报错 -8003: 缺少本地或者远程归档 解决方案
数据库·c++·dm·备份复原
yy_xzz2 小时前
【Linux开发】I/O 复用:select 模型
linux·c++·select
小肝一下2 小时前
每日两道力扣,day6
数据结构·c++·算法·leetcode·双指针·hot100
ambition202422 小时前
【算法详解】飞机降落问题:DFS剪枝解决调度问题
c语言·数据结构·c++·算法·深度优先·图搜索算法
I Promise342 小时前
C++ 基础数据结构与 STL 容器详解
开发语言·数据结构·c++
人道领域3 小时前
【LeetCode刷题日记】242.字母异位词
算法·leetcode·职场和发展
旖-旎3 小时前
链表(两两交换链表中的节点)(2)
数据结构·c++·学习·算法·链表·力控
XWalnut3 小时前
LeetCode刷题 day8
算法·leetcode·职场和发展