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

每日一题——缺失的第一个正数

缺失的第一个正数

        • 问题描述
        • 示例
        • 输入与输出
      • 解题思路
      • 代码实现
      • 代码解析
        • 1. **原地交换逻辑**
        • 2. **查找缺失的正整数**
        • 3. **特殊情况**
      • 示例分析
        • 示例1
        • 示例2
        • 示例3
      • 注意事项
        • 错误的交换顺序
        • 正确的交换顺序
        • 核心区别
      • 总结

问题描述

给定一个未排序的整数数组nums,请你找出其中没有出现的最小正整数。要求实现时间复杂度为O(n),并且只使用常数级别的额外空间。

示例
  1. 输入: nums = [1, 2, 0]
    输出: 3
    解释: 范围 [1, 2] 中的数字都在数组中,缺失的最小正整数为3。

  2. 输入: nums = [3, 4, -1, 1]
    输出: 2
    解释: 数组中包含1,但缺失2。

  3. 输入: nums = [7, 8, 9, 11, 12]
    输出: 1
    解释: 最小的正整数1没有出现。

输入与输出
  • 输入:一个整数数组nums,长度在[1, 10^5]范围内,数组中的每个元素范围为[-2^31, 2^31 - 1]
  • 输出:一个整数,表示数组中缺失的最小正整数。

解题思路

为了在O(n)时间复杂度和常数空间复杂度下解决问题,我们可以利用数组的索引作为辅助信息。具体步骤如下:

  1. 原地交换:
    将数组中的每个正整数放到其对应的索引位置。例如,数字1应该放到索引0的位置,数字2应该放到索引1的位置,依此类推。

  2. 遍历数组:
    遍历数组,找到第一个不满足nums[i] == i + 1的索引,返回i + 1作为缺失的正整数。

  3. 特殊情况:
    如果所有数字都正确,返回numsSize + 1


代码实现

以下是C语言的实现代码,包含详细注释:

int firstMissingPositive(int* nums, int numsSize) {
    // 第一轮循环:将每个正整数放到其对应的索引位置
    for (int i = 0; i < numsSize; i++) {
        // 使用 while 循环确保每次交换后重新检查当前 nums[i]
        while (nums[i] > 0 && nums[i] <= numsSize && nums[nums[i] - 1] != nums[i]) {
            // 交换 nums[i] 和 nums[nums[i] - 1]
            int tmp = nums[nums[i] - 1];
            nums[nums[i] - 1] = nums[i];
            nums[i] = tmp;
        }
    }

    // 第二轮循环:查找第一个不满足 nums[i] == i + 1 的索引
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] != i + 1) {
            return i + 1; // 返回缺失的正整数
        }
    }

    // 如果所有数字都正确,返回 numsSize + 1
    return numsSize + 1;
}

代码解析

1. 原地交换逻辑
while (nums[i] > 0 && nums[i] <= numsSize && nums[nums[i] - 1] != nums[i]) {
    int tmp = nums[nums[i] - 1];
    nums[nums[i] - 1] = nums[i];
    nums[i] = tmp;
}
  • 条件解析:
    • nums[i] > 0 && nums[i] <= numsSize:确保当前数字是有效的正整数,并且在数组范围内。
    • nums[nums[i] - 1] != nums[i]:避免重复交换,确保交换操作有意义。
  • 交换逻辑:
    • 使用临时变量tmp保存nums[nums[i] - 1]的值。
    • nums[i]放到其正确的位置nums[nums[i] - 1]
    • tmp赋值给nums[i],完成交换。
2. 查找缺失的正整数
for (int i = 0; i < numsSize; i++) {
    if (nums[i] != i + 1) {
        return i + 1; // 返回缺失的正整数
    }
}
  • 遍历数组,检查每个数字是否在其正确的位置。
  • 如果发现nums[i] != i + 1,则返回i + 1作为缺失的正整数。
3. 特殊情况
return numsSize + 1;
  • 如果所有数字都正确,说明缺失的正整数是numsSize + 1

示例分析

示例1

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

  1. 第一轮循环后,数组变为[1, 2, 0](无需交换)。
  2. 第二轮循环中,nums[2] = 0 != 3,返回3

输出: 3

示例2

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

  1. 第一轮循环后,数组变为[1, -1, 3, 4]
  2. 第二轮循环中,nums[1] = -1 != 2,返回2

输出: 2

示例3

输入: nums = [7, 8, 9, 11, 12]
过程:

  1. 第一轮循环后,数组仍为[7, 8, 9, 11, 12](无需交换)。
  2. 第二轮循环中,nums[0] = 7 != 1,返回1

输出: 1


注意事项

错误的交换顺序
int tmp = nums[i];
nums[i] = nums[nums[i] - 1];
nums[nums[i] - 1] = tmp;

问题:
在第二步中,nums[i] 被修改了,导致第三步的索引 nums[i] - 1 变成了错误的值。因为 nums[i] 已经被改过,所以后续的交换会出错。

正确的交换顺序
int tmp = nums[nums[i] - 1];
nums[nums[i] - 1] = nums[i];
nums[i] = tmp;

正确原因:
在第一步中,先保存了目标位置的值 nums[nums[i] - 1]
在第二步中,直接把 nums[i] 放到目标位置。
在第三步中,把之前保存的值赋给 nums[i]
关键: 这样不会提前修改 nums[i],所以索引始终是正确的。

核心区别
  • 错误的交换:先改了 nums[i],导致后续索引错乱。
  • 正确的交换:先保存目标位置的值,再交换,不会错乱。

简单来说,就是不要提前修改 nums[i],否则索引会乱掉

  1. 边界条件:

    • 确保交换时的索引nums[i] - 1始终在有效范围内([0, numsSize - 1])。
  2. 时间复杂度:

    • 每个数字最多被交换两次(一次放到正确位置,一次被交换出来),因此总时间复杂度为O(n)。

总结

通过原地交换的方式,我们可以高效地将数组中的正整数放到其对应的位置,并通过一次遍历找到缺失的最小正整数。这种方法满足了O(n)时间复杂度和常数空间复杂度的要求,适用于解决此类问题。


相关文章:

  • Taro React组件开发 —— RuiNoticeBar 通知栏
  • K8S高可用集群-小白学习之二进制部署(ansible+shell)
  • T31ZC 君正SOC芯片 应用于智能家居、工业控制等 满足各种嵌入式应用的需求 提供样品测试+软硬件资料
  • docker-compose安装redis-主从+哨兵(3台虚拟机一主两从)
  • 深度学习模型组件-RevNorm-可逆归一化(Reversible Normalization)
  • 行为模式---迭代器模式
  • MySQL 主主复制与 Redis 环境安装部署
  • 开发模型与测试模型
  • 原码、反码和补码的介绍和区别
  • pycharm找不到conda可执行文件
  • 系统架构设计师—数据库基础篇—数据库的控制功能
  • 【形态学操作中的开运算和闭运算详细讲解】
  • Windows设置目录及子目录大小写不敏感暨git克隆报错同名文件已存在的解决办法
  • Flink MysqlCDC和OracleCDC对比
  • 虚拟卡 WildCard (野卡) 保姆级开卡教程
  • QT day5
  • 当夸克让搜索学会深度思考,AI搜索掀开新篇章
  • 分布式ID生成方案:数据库号段、Redis与第三方开源实现
  • 代码随想录算法训练营第35天 | 01背包问题二维、01背包问题一维、416. 分割等和子集
  • 【芯片设计】处理器芯片大厂前端设计工程师面试记录·20250307
  • 通化 网站建设/交换友链
  • 那个比特币网站可以做杠杆/网络服务商主要包括
  • 牛天下网站建设/关键字排名优化工具
  • wordpress登录后台闪退/整站优化关键词排名
  • 做中医诊所网站/上海网站建设制作
  • 2017做电商做什么网站/网页制作费用大概多少