从图书馆编目到数组搜索:探索缺失的第一个正整数

生活中的算法

想象你是一位图书馆管理员,正在整理一排连续编号的图书。这些书应该从1号开始按顺序排列,但是有些编号的书不见了。你的任务是找出第一个缺失的编号。这就像是在做点名,发现第一个没来上课的同学。

这个场景在生活中很常见。比如:

  • 餐厅服务员查看哪个桌号是第一个空位
  • 停车场管理员寻找第一个空闲的车位号
  • 学校给新生分配第一个未使用的学号
  • 医院为病人安排第一个可用的就诊序号

问题描述

LeetCode第41题"缺失的第一个正整数"是这样描述的:给你一个未排序的整数数组 nums,请你找出其中没有出现的最小的正整数。请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

例如:

输入:nums = [3,4,-1,1]
输出:2
解释:数组中有1,3,4,所以第一个缺失的正整数是2。 输入:nums = [7,8,9,11,12]
输出:1
解释:数组中没有1,所以缺失的第一个正整数是1。

最直观的解法:排序后遍历

就像整理图书时,先把所有的书按编号排好序,然后从1开始检查,看哪个编号最先空缺。

让我们用一个简单的例子来理解:

原数组:[3,1,4,-1]
1. 先排序(只考虑正数):[1,3,4]
2. 从1开始检查:
- 1存在
- 2不存在,找到答案!

优化解法:原地标记

仔细思考会发现一个关键点:如果数组长度为n,那么答案一定在[1, n+1]范围内。就像有10个学生的班级,第一个缺席的学号最大不会超过11。

我们可以把数组本身作为标记板,把每个数放到它应该在的位置上(就像把每本书放到对应的编号位置)。

原地标记的原理

  1. 把每个在[1,n]范围内的数x放到索引x-1的位置
  2. 再次遍历,第一个不在对应位置的数就指示了缺失的最小正整数

    这就像是:
  • 先把每本书放到它编号对应的书架位置
  • 然后从1号位置开始检查,找到第一个空位置

示例演示

用nums = [3,4,-1,1]来说明:

1. 开始移动元素:
[3,4,-1,1] 把3放到索引2
[3,4,3,1] 把4放到索引3
[3,1,3,4] 把1放到索引0
[1,3,3,4] 2. 再次遍历,检查每个位置:
位置0:期望1,实际1,正确
位置1:期望2,实际3,找到答案2!

Java代码实现

public int firstMissingPositive(int[] nums) {
int n = nums.length; // 第一遍遍历:把每个数放到它应该在的位置
for (int i = 0; i < n; i++) {
// 当前数在有效范围内,且不在正确位置上
while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
// 交换到正确位置
int temp = nums[nums[i] - 1];
nums[nums[i] - 1] = nums[i];
nums[i] = temp;
}
} // 第二遍遍历:找出第一个不在正确位置上的数
for (int i = 0; i < n; i++) {
if (nums[i] != i + 1) {
return i + 1;
}
} // 如果都正确,返回n+1
return n + 1;
}

解法比较

让我们比较这两种方法:

排序后遍历:

  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)
  • 优点:思路直观,易于理解
  • 缺点:不满足时间复杂度要求

原地标记:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
  • 优点:满足所有要求,不需要额外空间
  • 缺点:实现略微复杂,需要仔细处理边界情况

解题技巧总结

这道题给我们的启示:

  1. 思考数据的取值范围很重要
  2. 有时候可以把数组本身当作标记数组使用
  3. 位置和值的对应关系常常能带来灵感
  4. 不要害怕修改原数组,有时这是提高效率的关键

类似的问题还有:

  • 数组中重复的数字
  • 找到所有数组中消失的数字
  • 寻找重复数

小结

通过缺失的第一个正整数这道题,我们学会了一个重要的思维方式:有时候看似需要额外空间的问题,可以通过巧妙利用输入数组本身来解决。这种思维不仅在这道题中有用,在处理其他需要标记或计数的问题时也很有启发。记住,当遇到需要找寻特定范围内缺失数字的问题时,考虑能否利用数组本身来存储信息!


作者:忍者算法

公众号:忍者算法

完整题解项目 :https://github.com/ninjaAlgorithm/LeetCode-Solutions-Hot-100

【忍者算法】从图书馆编目到数组搜索:探索缺失的第一个正整数|LeetCode 41 缺失的第一个正整数的更多相关文章

  1. Java实现 蓝桥杯VIP 算法提高 递归倒置字符数组

    算法提高 递归倒置字符数组 时间限制:1.0s 内存限制:512.0MB 问题描述 完成一个递归程序,倒置字符数组.并打印实现过程 递归逻辑为: 当字符长度等于1时,直接返回 否则,调换首尾两个字符, ...

  2. 【算法入门】广度/宽度优先搜索(BFS)

    广度/宽度优先搜索(BFS) [算法入门] 1.前言 广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历策略.因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较 ...

  3. js算法初窥03(简单搜索及去重算法)

    前面我们了解了一些常用的排序算法,那么这篇文章我们来看看搜索算法的一些简单实现,我们先来介绍一个我们在实际工作中一定用到过的搜索算法--顺序搜索. 1.顺序搜索 其实顺序搜索十分简单,我们还是以第一篇 ...

  4. LeetCode初级算法的Python实现--排序和搜索、设计问题、数学及其他

    LeetCode初级算法的Python实现--排序和搜索.设计问题.数学及其他 1.排序和搜索 class Solution(object): # 合并两个有序数组 def merge(self, n ...

  5. 【算法】C语言实现数组的动态分配

    C语言实现数组的动态分配 作者:白宁超 2016年10月27日20:13:13 摘要:数据结构和算法对于编程的意义不言而喻,具有指导意义的.无论从事算法优化方向研究,还是大数据处理,亦或者网站开发AP ...

  6. php 算法之切割数组,不用array_chunk(),算法之二,取数组的差值,不用array_diff()

    用php写算法切割数组,不用array_chunk();算法例如以下所看到的. <?php //$array 数组 //$size 每一个数组的个数 //每一个数组元素是否默认键值 functi ...

  7. C/C++面试之算法系列--去除数组中的重复数字

    去除数组中的重复数字 Sailor_forever  sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/2008/ ...

  8. 求逆序对常用的两种算法 ----归并排 & 树状数组

    网上看了一些归并排求逆序对的文章,又看了一些树状数组的,觉得自己也写一篇试试看吧,然后本文大体也就讲个思路(没有例题),但是还是会有个程序框架的 好了下面是正文 归并排求逆序对 树状数组求逆序对 一. ...

  9. java数据结构和算法编程作业系列篇-数组

    /** * 编程作业 2.1 向highArray.java程序(清单2.3)的HighArray类添加一个名为getMax()的方法,它返回 数组中最大关键字的值,当数组为空时返回-1.向main( ...

  10. Java数据结构和算法(二):数组

    上篇博客我们简单介绍了数据结构和算法的概念,对此模糊很正常,后面会慢慢通过具体的实例来介绍.本篇博客我们介绍数据结构的鼻祖——数组,可以说数组几乎能表示一切的数据结构,在每一门编程语言中,数组都是重要 ...

随机推荐

  1. npm报错error:0308010C:digital envelope routines::unsupported

    error:0308010C:digital envelope routines::unsupported 出现这个错误是因为 node.js V17版本中最近发布的OpenSSL3.0, 而Open ...

  2. VulnHub-Sick0s1.1解法二shellshock漏洞

    免责声明 本博客提供的所有信息仅供学习和研究目的,旨在提高读者的网络安全意识和技术能力.请在合法合规的前提下使用本文中提供的任何技术.方法或工具.如果您选择使用本博客中的任何信息进行非法活动,您将独自 ...

  3. 编程辅助工具之Kite

    python作为一门门槛很低但又功能强大的编程语言,现在已经得到了非常广泛的使用,但是它的常用库非常多,而且往往更新后许多方法都有所变化,因此想要记住其大部分函数的用法对于大部分人来说比较困难,因而会 ...

  4. Mac之终端工具iterm2

    1. 安装 iTerm2 下载地址:https://www.iterm2.com/downloads.html 下载的是压缩文件,解压后是执行程序文件,你可以直接双击,或者直接将它拖到 Applica ...

  5. JPEG格式研究——(2)JPEG文件格式

    JPEG文件除了图像数据之外,还保存了与图片相关的各种信息,这些信息通过不同类型的TAG存储在文件中. TAG JPEG通过TAG标记压缩书记之外的信息.所有的TAG都包含一个TAG类型,TAG类型大 ...

  6. 记一次 .NET某hdp智能柜系统 卡死分析

    一:背景 1. 讲故事 停了一个月时间没有更新博客了,主要是这段时间有些许事情导致心神不宁,我这个人也比较浮躁所以无法潜心修炼,事情如下: 被狗咬了 也不知道是不是出门没看黄历,在小区门口店里买烟,被 ...

  7. Epicor ERP成本稽核

    很多制造企业存在成本差异过大,公司要求提高成本准确率,以便为产品成本分析提供数据支撑. A. 成本现状:成本差异分析,工时.费率.制造差异等出现各种不同情况,造成差异过大. B. 以下是Epicor的 ...

  8. LeetCode题集-5 - 最长回文子串(一)

    题目:给你一个字符串 s,找到 s 中最长的回文子串. 这一题作为中等难度,常规解法对于大多数人应该都没有难度.但是其中也有超难的解决办法,下面我们就一起由易到难,循序渐进地来解这道题. 01.暴力破 ...

  9. 要构建此项目,必须安装以下工作负载: wasm-tools

    要构建此项目,必须安装以下工作负载: wasm-tools 要安装这些工作负载,请运行以下命令: dotnet workload restore AdminAPP C:\Program Files\d ...

  10. 如何在 duxapp 中开发一个兼容 RN 的动画库

    Taro 一直以来都没有一个能兼容 RN 的动画方案,duxapp 中扩展了 createAnimation 方法,让这个方法兼容了 RN 端,下面让我们来看看实现思路 createAnimation ...