数组作为哈希表的妙用:寻找缺失的第一个正数
数组作为哈希表的妙用:寻找缺失的第一个正数
大家好,我是Echo_Wish,今天我们来探讨一个经典的算法问题——“缺失的第一个正数”。听起来可能有点简单,但它实际上是一个非常有意思且富有挑战性的题目,在面试中常常会碰到。更重要的是,这个问题能够帮助我们更好地理解数组和哈希表的妙用,今天我们将通过实际的代码演示,看看如何高效解决这个问题。
问题描述
题目要求我们在一个无序整数数组中,找到缺失的第一个正整数。比如,给定数组 [1, 2, 0],缺失的第一个正整数是 3,因为数组中没有 3,而且 1 和 2 都在其中。
这个问题有一个关键点:我们不仅要找到缺失的正数,而且还要考虑高效性,让我们能够在 O(n) 的时间复杂度下解决问题。
思考与优化
一开始,我想到了一个直接的办法——使用哈希表。具体来说,我们可以把数组中的元素都记录到哈希表里,然后从 1 开始检查每个数字是否存在哈希表中。这样一来,查找每个元素的时间复杂度是 O(1),整体复杂度是 O(n),效率较高。
但问题在于:直接使用哈希表占用的空间较大。我们其实可以通过数组本身来模拟哈希表,从而降低空间复杂度。接下来,我们通过一个具体的方案来分析如何操作。
解决方案:用数组模拟哈希表
由于题目要求我们找到缺失的第一个正整数,我们知道正整数的范围是从 1 开始,一直到数组的长度 n。因此,我们可以通过将数组的每个元素与数组下标一一对应来实现模拟哈希表的功能。
解决步骤
-
过滤无效值
由于我们只关心正整数1到n,任何小于1或大于n的值都不需要关心,因此我们可以直接将它们忽略。 -
将数组值放到正确的位置
我们可以将每个元素放到它应该去的位置,比如数字1放到下标0,数字2放到下标1,依此类推。这样,当我们遍历数组时,所有值都应该出现在它们对应的下标位置。 -
找到缺失的正整数
遍历一遍处理过的数组,找到第一个不在正确位置的值,那么它对应的下标就是缺失的第一个正整数。
代码实现
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或大于n的值替换成n + 1,这是因为在我们的问题范围内,这些数字不可能是缺失的第一个正整数。 -
数组重排
在第二步中,我们将每个数x放到下标x-1的位置,通过将其变成负数来标记它已经出现在数组中。这是模拟哈希表的一种方式,借助数组的空间和下标直接存储信息。 -
查找缺失的数字
在最后一步,我们遍历数组,查找第一个正数,它的下标就是缺失的第一个正整数。
时间与空间复杂度分析
- 时间复杂度:O(n),我们只需要遍历数组三次。
- 空间复杂度:O(1),我们没有使用额外的哈希表,而是直接在原数组上进行了操作。
举个例子
让我们看一个具体的例子:
假设输入是 [3, 4, -1, 1],按照我们的思路,第一步过滤无效值,数组变成 [3, 4, 5, 1]。然后,我们将每个值放到它该在的位置。经过第二步处理后,数组变成 [-3, -4, 5, -1]。最后,我们遍历数组,发现位置 2 没有被标记(值为 5),因此缺失的第一个正整数是 2。
总结
通过这个问题,我们不难发现,数组可以作为一种高效的哈希表,通过巧妙地利用下标来存储信息,可以大大减少空间复杂度。这种思路不仅适用于“缺失的第一个正数”问题,也能在其他类似的算法题中找到应用。希望这篇文章能够帮助你更好地理解如何在面试或实际项目中利用数组来优化算法。
相关文章:
数组作为哈希表的妙用:寻找缺失的第一个正数
数组作为哈希表的妙用:寻找缺失的第一个正数 大家好,我是Echo_Wish,今天我们来探讨一个经典的算法问题——“缺失的第一个正数”。听起来可能有点简单,但它实际上是一个非常有意思且富有挑战性的题目,在面试中常常会碰…...
物化视图详解:数据库性能优化的利器
物化视图(Materialized View)作为数据库性能优化的核心手段,通过预计算和存储查询结果,显著提升了复杂查询的效率。本文将深入剖析物化视图的工作原理、应用场景及最佳实践,帮助企业在合适的场景中充分发挥其性能优势。…...
【C++】类和对象(匿名对象)
匿名对象 用 类型(实参) 定义出来的对象叫做匿名对象,相比之前我们定义的 类型 对象名(实参) 定义出来叫有名对象匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。 class A { public:A(int a 0):_a…...
一文读懂 GPT 与 BERT:预训练逻辑及差异剖析
在自然语言处理(NLP)领域,预训练语言模型GPT(Generative Pretrained Transformer)和 BERT(Bidirectional Encoder Representations from Transformers)作为杰出代表,备受关注。本文将…...
【算法】十大排序算法(含时间复杂度、核心思想)
以下是 **十大经典排序算法** 的时间复杂度、空间复杂度及稳定性总结,适用于面试快速回顾:排序算法对比表 排序算法最佳时间复杂度平均时间复杂度最差时间复杂度空间复杂度稳定性核心思想冒泡排序O(n)O(n)O(n)O(1)稳定相邻元素交换,大数沉底…...
渐进式滑坡多场信息演化特征与数据挖掘研究
标题:渐进式滑坡多场信息演化特征与数据挖掘研究 内容:1.摘要 摘要:在地质灾害频发的背景下,研究渐进式滑坡多场信息演化特征与数据挖掘具有重要的实际意义。本研究旨在深入探究渐进式滑坡在不同阶段的多场信息(如应力场、位移场、渗流场等&…...
蓝桥杯备考-》单词接龙
很明显,这道题是可以用DFS来做的,我们直接暴力搜索,但是这里有很多点是我们需要注意的。 1.我们如何确定两个单词能接上? 比如touch和choose 应该合成为touchoose 就是这样两个单词,我们让一个指针指着第一个字符串…...
解锁C++模板参数:开启泛型编程新世界
目录 C++ 模板:编程世界的瑞士军刀 一、模板参数初相识 1.1 类型参数 1.2 非类型参数 1.3 模板模板参数 二、模板参数推导大揭秘 2.1 推导规则深度剖析 2.2 推导成功场景展示 2.3 推导失败场景解析 三、模板参数实战应用 3.1 通用算法实现 3.2 容器类设计 3.3 元…...
计算机视觉yolov8模型应用-学习笔记
计算机视觉yolov8模型应用-学习笔记 YOLOv8是由Ultralytics公司在2023年1月10日发布的一款深度学习模型。它是YOLOv5的重大更新版本,支持图像分类、物体检测和实例分割任务。这一版本在发布前就受到了广泛关注,并在发布后迅速成为目标检测领域的热门…...
【网络层协议】NAT技术内网穿透
IP地址数量限制 我们知道,IP地址(IPv4)是一个4字节32位的整数,那么一共只有2^32也就是接近43亿个IP地址,而TCP/IP协议栈规定,每台主机只能有一个IP地址,这就意味着,一共只有不到43亿…...
SQL中的索引是什么
在 SQL 中,索引(Index) 是一种用于加速数据检索的数据库对象,通过建立特定的数据结构(如 B树、哈希表等),帮助数据库系统快速定位目标数据。以下是关于索引的详细分类、工作原理、使用场景和最佳…...
TensorFlow面试题及参考答案
目录 什么是 TensorFlow 的计算图?详细描述 TensorFlow 计算图的组成结构(节点、边、会话) 它与动态图(Eager Execution)的区别是什么?TensorFlow 静态计算图与动态图(Eager Execution)的区别及适用场景是什么? 解释张量(Tensor)的概念及其在 TensorFlow 中的作用…...
go-zero学习笔记
内容不多,只有部分笔记,剩下的没有继续学下去,包括路由与处理器、日志中间件、请求上下文 文章目录 1、go-zero核心库1.1 路由与处理器1.2 日志中间件1.3 请求上下文 1、go-zero核心库 1.1 路由与处理器 package mainimport ("github…...
在Ubuntu 22.04 中安装Docker的详细指南
这里写目录标题 前言一、安装 Docker1. 卸载旧版本(如有)2. 更新系统并安装依赖工具3. 添加 Docker 官方 GPG 密钥4. 设置 Docker 仓库5. 安装 Docker Engine6. 验证安装 二、配置 Docker 镜像加速1. 修改 Docker 配置文件2. 重启 Docker 服务3. 验证加速…...
十亿级流量削峰实战:LinkedBlockingQueue缓冲池的工程化实现
《十亿级流量削峰实战:LinkedBlockingQueue缓冲池的工程化实现》 本文将以电商秒杀系统为背景,深度解析如何通过LinkedBlockingQueue构建百万QPS级异步缓冲系统,包含容量计算模型、拒绝策略选择、监控埋点方案等完整实施细节,并提…...
深入理解 C++11 智能指针:独占、共享与弱引用的完美管理
文章目录 std::unique_ptr(独占式智能指针)std::shared_ptr(共享式智能指针)std::weak_ptr(弱引用智能指针)示例展示:智能指针的原理内存泄漏**什么是内存泄漏,内存泄漏的危害****如…...
AI Agent开发大全第四课-提示语工程:从简单命令到AI对话的“魔法”公式
什么是提示语工程?一个让AI“听话”的秘密 如果你曾经尝试过用ChatGPT或者其他大语言模型完成任务,那么你一定遇到过这样的情况:明明你的问题是清晰的,但答案却离题万里;或者你认为自己提供的信息足够详尽,可结果还是不理想。问题出在哪?很多时候并不是因为AI不够聪明,…...
大模型架构记录 【综述-文字版】
名词解释: Prompt :提示词,是一个非常关键的概念,它指的是用户输入的文本或指令,用于引导语言模型生成相应的回答或执行特定任务。 Prompt Engineering:(提示工程) 是一种通过设计…...
WebSocket:开启实时通信的新篇章
在当今的互联网应用中,实时交互已经成为不可或缺的一部分。无论是实时的在线聊天、股票行情更新,还是多人在线游戏,都需要一种高效的双向通信机制。而这正是 WebSocket 的用武之地。 本文将带你深入了解 WebSocket,探索其工作原理…...
【论文笔记】Transformer
Transformer 2017 年,谷歌团队提出 Transformer 结构,Transformer 首先应用在自然语言处理领域中的机器翻译任务上,Transformer 结构完全构建于注意力机制,完全丢弃递归和卷积的结构,这使得 Transformer 结构效率更高…...
使用CSS3实现炫酷的3D翻转卡片效果
使用CSS3实现炫酷的3D翻转卡片效果 这里写目录标题 使用CSS3实现炫酷的3D翻转卡片效果项目介绍技术要点分析1. 3D空间设置2. 核心CSS属性3. 布局和定位 实现难点和解决方案1. 3D效果的流畅性2. 卡片内容布局3. 响应式设计 性能优化建议浏览器兼容性总结 项目介绍 在这个项目中…...
SpringSecurity——基于角色权限控制和资源权限控制
目录 基于角色权限控制 1.1 自定义 UserDetailsService 1.2 加载用户角色 1.3. 给角色配置能访问的资源(使用切面拦截,使用注解) 总结 资源权限控制 2.2. 需要有一个用户;(从数据库查询用户) 2.2 基…...
红宝书第十一讲:超易懂版「ES6类与继承」零基础教程:用现实例子+图解实现
红宝书第十一讲:超易懂版「ES6类与继承」零基础教程:用现实例子图解实现 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、ES6类的核心语法:把事物抽象成“模板” 想象你要设…...
通信基本概念
系列文章目录 文章目录 系列文章目录前言一、消息、信息和信号1.消息的定义2.信号的定义3.信息的定义4.消息、信息和信号的关系5.通信的目标 二、通信系统的组成模型1.一般通信系统模型2.各部分说明3.模拟通信系统模型4.数字通信系统模型4.数字通信的特点数字通信的优点数字通信…...
Python为Word文档添加书签并打包成exe
背景简述 由于一些工作场景,需要从多个Word文档中找到出现的关键词,并阅读关键词的上下文内容。文件可能几十个,手动操作太要命了。所以python尝试处理。 目录 背景简述思路第一步、功能实现结果验证 第二步、打包成exe2-1、基础准备2-2、打…...
ROS导航工具包Navigation
一,安装 Navigation工具包包含在 navigation 元功能包中。你可以通过以下命令安装: sudo apt-get install ros-noetic-navigation 如果你使用的是其他ROS版本(如Melodic),将 noetic 替换为对应的版本名称(…...
BigEvent项目后端学习笔记(二)文章分类模块 | 文章分类增删改查全流程解析(含优化)
📖 模块概述 文章分类模块包括 新增文章分类、文章分类列表、获取文章分类详情、更新文章分类、删除文章分类 功能。本篇对于原项目进行了代码优化,将原先写在 Controller 层的业务逻辑代码迁移至了 Service 层。 🛠️ 技术实现要点 分组校…...
资金管理策略思路
详细描述了完整交易策略的实现细节,主要包括输入参数、变量定义、趋势判断、入场与出场条件、止损与止盈设置等多个方面。 输入参数(Input): EntryFrL (.6):多头入场的前一日波动范围的倍数。 EntryFrS (.3)࿱…...
UI-TARS与Midscene.js自动化探索
结合 Midscene.js 和 UI-TARS 大模型 实现 UI 页面自动化的可实施方案,涵盖环境配置、核心流程、代码示例及优化建议: 一、环境配置与工具集成 安装 Midscene.js 方式一:通过 Chrome 插件快速安装(适用于浏览器自动化场景&#x…...
关于 URH(Universal Radio Hacker) 的详细介绍、安装指南、配置方法及使用说明
URH:开源无线电协议分析工具 一、URH简介 URH 是一款开源的 无线电协议分析工具,专注于解码、分析和逆向工程无线通信协议(如 Wi-Fi、蓝牙、RFID、LoRa、Zigbee 等)。它支持信号捕获、协议树构建、数据可视化及自定义脚本扩展&a…...
