数组作为哈希表的妙用:寻找缺失的第一个正数

数组作为哈希表的妙用:寻找缺失的第一个正数

大家好,我是Echo_Wish,今天我们来探讨一个经典的算法问题——“缺失的第一个正数”。听起来可能有点简单,但它实际上是一个非常有意思且富有挑战性的题目,在面试中常常会碰到。更重要的是,这个问题能够帮助我们更好地理解数组和哈希表的妙用,今天我们将通过实际的代码演示,看看如何高效解决这个问题。

问题描述

题目要求我们在一个无序整数数组中,找到缺失的第一个正整数。比如,给定数组 [1, 2, 0],缺失的第一个正整数是 3,因为数组中没有 3,而且 12 都在其中。

这个问题有一个关键点:我们不仅要找到缺失的正数,而且还要考虑高效性,让我们能够在 O(n) 的时间复杂度下解决问题。

思考与优化

一开始,我想到了一个直接的办法——使用哈希表。具体来说,我们可以把数组中的元素都记录到哈希表里,然后从 1 开始检查每个数字是否存在哈希表中。这样一来,查找每个元素的时间复杂度是 O(1),整体复杂度是 O(n),效率较高。

但问题在于:直接使用哈希表占用的空间较大。我们其实可以通过数组本身来模拟哈希表,从而降低空间复杂度。接下来,我们通过一个具体的方案来分析如何操作。

解决方案:用数组模拟哈希表

由于题目要求我们找到缺失的第一个正整数,我们知道正整数的范围是从 1 开始,一直到数组的长度 n。因此,我们可以通过将数组的每个元素与数组下标一一对应来实现模拟哈希表的功能。

解决步骤

  1. 过滤无效值
    由于我们只关心正整数 1n,任何小于 1 或大于 n 的值都不需要关心,因此我们可以直接将它们忽略。

  2. 将数组值放到正确的位置
    我们可以将每个元素放到它应该去的位置,比如数字 1 放到下标 0,数字 2 放到下标 1,依此类推。这样,当我们遍历数组时,所有值都应该出现在它们对应的下标位置。

  3. 找到缺失的正整数
    遍历一遍处理过的数组,找到第一个不在正确位置的值,那么它对应的下标就是缺失的第一个正整数。

代码实现

def first_missing_positive(nums):n = len(nums)# Step 1: 将无效值转换为n+1,表示这些值不参与计算for i in range(n):if nums[i] <= 0 or nums[i] > n:nums[i] = n + 1# Step 2: 将每个数字放到它对应的位置for i in range(n):val = abs(nums[i])if 1 <= val <= n:# 放置到正确的索引位置nums[val - 1] = -abs(nums[val - 1])  # 变成负值,表示已出现# Step 3: 找到第一个未被标记的位置for i in range(n):if nums[i] > 0:return i + 1  # 返回缺失的正整数# 如果所有位置都已经有值,说明缺失的正整数是n+1return n + 1# 示例测试
nums = [1, 2, 0]
print(first_missing_positive(nums))  # 输出 3nums = [3, 4, -1, 1]
print(first_missing_positive(nums))  # 输出 2

代码解析

  1. 过滤无效值
    我们通过遍历数组,将所有小于 1 或大于 n 的值替换成 n + 1,这是因为在我们的问题范围内,这些数字不可能是缺失的第一个正整数。

  2. 数组重排
    在第二步中,我们将每个数 x 放到下标 x-1 的位置,通过将其变成负数来标记它已经出现在数组中。这是模拟哈希表的一种方式,借助数组的空间和下标直接存储信息。

  3. 查找缺失的数字
    在最后一步,我们遍历数组,查找第一个正数,它的下标就是缺失的第一个正整数。

时间与空间复杂度分析

  • 时间复杂度:O(n),我们只需要遍历数组三次。
  • 空间复杂度:O(1),我们没有使用额外的哈希表,而是直接在原数组上进行了操作。

举个例子

让我们看一个具体的例子:

假设输入是 [3, 4, -1, 1],按照我们的思路,第一步过滤无效值,数组变成 [3, 4, 5, 1]。然后,我们将每个值放到它该在的位置。经过第二步处理后,数组变成 [-3, -4, 5, -1]。最后,我们遍历数组,发现位置 2 没有被标记(值为 5),因此缺失的第一个正整数是 2

总结

通过这个问题,我们不难发现,数组可以作为一种高效的哈希表,通过巧妙地利用下标来存储信息,可以大大减少空间复杂度。这种思路不仅适用于“缺失的第一个正数”问题,也能在其他类似的算法题中找到应用。希望这篇文章能够帮助你更好地理解如何在面试或实际项目中利用数组来优化算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/38734.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git tag以及git

git tag 以及git 一、先说收获吧 1. git bash 在windows上 类似于linux的bash提供的shell命令行窗口&#xff0c;可以执行很多linux命令&#xff0c;cd pwd ls vim cat touch mkdir&#xff0c;还可以用正则匹配查看标签。相当于在windows上装了一个小的linux。git init myproj…

[动手学习深度学习]28. 批量归一化

当前所有的深度学习网络&#xff0c;或多或少都用了批归一化操作 批归一化的思想不新&#xff0c;但是这个特定的层是16年左右出现的&#xff0c;在这之后&#xff0c;发现他对深度学习算法性能的提升非常有效 概念理解 这是一个网络的结构&#xff1a; 当数据很深的时候&am…

AI比人脑更强,因为被植入思维模型【17】万物联系思维模型

万物联系,万物,并不孤立。 定义 万物联系思维模型是一种强调世界上所有事物都相互关联、相互影响的思维方式。它认为任何事物都不是孤立存在的,而是与周围的环境、其他事物以及整个宇宙构成一个有机的整体。这种联系不仅包括直接的因果关系,还涵盖了间接的、潜在的、动态的…

昆仑技术重构AI大模型落地范式,长期作“加法”迎来国产生态化“拐点”

作者 | 曾响铃 文 | 响铃说 DeepSeek的爆火&#xff0c;在业内迅速掀起了一场国产化的变革。“国产大模型国产算力”软硬协同的范式正在被重构&#xff0c;AI产业国产化的含金量持续提升&#xff0c;越来越多的企业在这一趋势下加速走上数智化转型路径。 其中&#xff0c;以…

【C++初阶】---类和对象(上)

1.类的定义 1.1类的定义格式 • class为定义类的关键字&#xff0c;Data为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或者成员函数。 •…

常见中间件漏洞(tomcat)

CVE-2017-12615 当在Tomcat的conf&#xff08;配置目录下&#xff09;/web.xml配置文件中添加readonly设置为false时&#xff0c;将导致该漏洞产生&#xff0c;&#xff08;需要允许put请求&#xff09; , 攻击者可以利用PUT方法通过精心构造的数据包向存在漏洞的服务器里面上传…

NSSCTF(MISC)——[NSSRound#4 SWPU]Type Message

相应的做题地址&#xff1a;https://www.nssctf.cn/problem/2478 得到4个wav文件 使用DTMF Decoder工具&#xff0c;对D.wav进行识别 随波逐流&#xff0c;发现九宫格键盘解码能够得到flag 对其他3个文件依次进行识别解码 最终得到fNSSCTF{DTMFISREALLYEASY}

C++核心语法快速整理

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要为学过多门语言玩家快速入门C 没有基础的就放弃吧。 全部都是精华&#xff0c;看完能直接上手改别人的项目。 输出内容 std::代表了这里的cout使用的标准库&#xff0c;避免不同库中的相同命名导致混乱 …

Matplotlib完全指南:数据可视化从入门到实战

目录 引言 一、环境配置与基础概念 1.1 安装Matplotlib 1.2 导入惯例 1.3 两种绘图模式 二、基础图形绘制 2.1 折线图&#xff08;Line Plot&#xff09; 2.2 柱状图&#xff08;Bar Chart&#xff09; 三、高级图表类型 3.1 散点图&#xff08;Scatter Plot&#xff…

C++:IO库

一、C IO库的架构 C标准库中的IO系统基于流&#xff08;Stream&#xff09;​的概念&#xff0c;分为三层结构&#xff1a; ​流对象​&#xff08;如cin, cout, fstream&#xff09;​流缓冲区​&#xff08;streambuf&#xff0c;负责底层数据处理&#xff09;​数据源/目的…

【STM32】SPI通信外设硬件SPI读写W25Q64

【STM32】SPI通信协议&W25Q64Flash存储器芯片&#xff08;学习笔记&#xff09;-CSDN博客 SPI通信外设 SPI外设简介 STM32内部集成了硬件SPI收发电路&#xff0c;可以由硬件自动执行时钟生成、数据收发等功能&#xff0c;减轻CPU的负担可配置8位/16位数据帧、高位先行/…

二叉树之树的高以及遍历

二叉树的高其实很简单就一句话&#xff1a; 从根节点到叶节点的最长路径中的边数就是二叉树的高 int FindHeight(Btree root){int leftheight;int rightheight;if(rootNULL){return -1;}else{leftheightFindHeight(root->left );rightheightFindHeight(root->right );}r…

DeepSeek技术架构解析:MoE混合专家模型

一、前言 2025年初&#xff0c;DeepSeek V3以557万美元的研发成本&#xff08;仅为GPT-4的1/14&#xff09;和开源模型第一的排名&#xff0c;在全球AI领域掀起波澜。其核心创新之一——混合专家模型&#xff08;Mixture of Experts, MoE&#xff09;的优化设计&#xff0c;不…

VMware主机换到高配电脑,高版本系统的问题

原来主机是i3 ,windows7系统&#xff0c;vmware 14.0,虚机系统是ubuntu 14.04。目标新机是i7 14700KF,windows11系统。原以为安装虚拟机&#xff0c;将磁盘文件&#xff0c;虚拟机配置文件拷贝过去可以直接用。 新目标主机先安装了vmware 15&#xff0c;运行原理虚机&#xff0…

数字化转型驱动卫生用品安全革新

当315晚会上晃动的暗访镜头揭露卫生巾生产车间里漂浮的异物、纸尿裤原料仓中霉变的碎屑时&#xff0c;这一触目惊心的场景无情地撕开了“贴身安全”的遮羞布&#xff0c;暴露的不仅是部分企业的道德缺失&#xff0c;更凸显了当前检测与监管体系的漏洞&#xff0c;为整个行业敲响…

VideoHelper 油猴脚本,重塑你的视频观看体验

VideoHelper 油猴脚本&#xff0c;重塑你的视频观看体验 在日常上网看视频时&#xff0c;你是否也被这些问题困扰&#xff1a;视频网站开头的广告又臭又长&#xff0c;找个合适的播放倍速要在一堆选项里翻半天&#xff0c;每次手动调音量、点全屏按钮繁琐又影响沉浸感&#xf…

(C语言)习题练习 sizeof 和 strlen

sizeof 上习题&#xff0c;不知道大家发现与上一张的习题在哪里不一样嘛&#xff1f; int main() {char arr[] "abcdef";printf("%zd\n", sizeof(arr));printf("%zd\n", sizeof(arr 0));printf("%zd\n", sizeof(*arr));printf(&…

Java多线程与高并发专题——使用 Future 有哪些注意点?Future 产生新的线程了吗?

Future 的注意点 1. 当 for 循环批量获取 Future 的结果时容易 block&#xff0c;get 方法调用时应使用 timeout 限制 对于 Future 而言&#xff0c;第一个注意点就是&#xff0c;当 for 循环批量获取 Future 的结果时容易 block&#xff0c;在调用 get方法时&#xff0c;应该…

STM32基础教程——PWM驱动LED呼吸灯

目录 前言 技术实现 原理图 接线图 代码实现 内容要点 PWM基本结构 开启外设时钟 配置GPIO端口 配置时基单元 初始化输出比较单元 输出PWM波形 输出比较通道重映射 前言 PWM(Pulse Width Modulation):一种通过调节脉冲信号的占空比&#xff08;高电平持续时间与整…

算法基础——栈

一、栈的概念 栈是⼀种只允许在⼀端进⾏数据插⼊和删除操作的线性表。 进⾏数据插⼊或删除的⼀端称为栈顶&#xff0c;另⼀端称为栈底。不含元素的栈称为空栈。进栈就是往栈中放⼊元素&#xff0c;出栈就是将元素弹出栈顶。 二、栈的模拟实现 1. 创建 本质还是线性表&#…