【LeetCode 热题 100】41. 缺失的第一个正数——(解法二)原地哈希

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

【LeetCode 热题 100】41. 缺失的第一个正数——(解法一)暴力解

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(N)
    • 空间复杂度:O(1)

整体思路

这段代码旨在高效地解决 “缺失的第一个正数” 问题。与上一个排序解法不同,此版本采用了一种称为 “原地哈希” (In-place Hashing)“循环排序” (Cyclic Sort) 的思想,能够在 O(N) 的时间复杂度和 O(1) 的空间复杂度内完成任务,是此问题的最优解。

算法的核心思想是:尝试将每个数字 x 放到它“应该”在的位置上。对于一个长度为 n 的数组,如果我们只关心 1n 的正整数,那么数字 1 应该在索引 0 的位置,数字 2 应该在索引 1 的位置,以此类推,数字 x 应该在索引 x-1 的位置。

算法的执行步骤如下:

  1. 原地重排数组

    • 算法通过一个 for 循环遍历数组。在 for 循环的内部,是一个 while 循环,这是算法的核心。
    • 对于当前位置 i 的数字 nums[i]
      • while 循环的条件:这个条件非常关键,它同时检查三件事:
        1. nums[i] >= 1 && nums[i] <= n:确保 nums[i] 是一个在 [1, n] 范围内的有效正数。我们只关心这些数字,任何超出这个范围的数字(负数、零、或大于 n 的数)都无需处理,因为它们不可能是 1n 范围内的缺失正数。
        2. nums[i] != nums[nums[i] - 1]:检查 nums[i] 是否已经在它正确的位置上。nums[i] 应该在的位置是 nums[i] - 1。如果 nums[i] 的值不等于 numsnums[i]-1 索引上的值,说明 nums[i] 还未归位。
      • 执行交换:如果 while 条件满足,就执行一次交换,将 nums[i]nums[nums[i] - 1] 的值互换。这个操作的目的就是将 nums[i] 送到它应该在的位置去。
    • 这个 while 循环会持续进行,直到当前 i 位置的数字不再满足交换条件(可能因为它已经归位,或者它是一个无效数字)。然后外层 for 循环才会进入下一个 i
  2. 查找缺失的正数

    • 当第一步的重排完成后,理想情况下,数组 nums 应该形如 [1, 2, 3, ..., n]
    • 接着,进行第二次遍历。在这个遍历中,检查每个位置 i 的值是否等于 i+1
    • 如果 nums[i] != i + 1,这意味着 i+1 这个正整数本应在这里,但它不在。由于我们已经把所有能归位的数字都归位了,这个不在位置上的 i+1 就是我们找到的第一个缺失的正数。直接返回 i+1
  3. 处理特殊情况

    • 如果在第二次遍历中,所有的数字都在它们正确的位置上(即 nums 就是 [1, 2, ..., n]),那么循环会正常结束。
    • 这说明 1n 所有的正数都存在,因此,缺失的第一个正数就是 n+1

完整代码

class Solution {/*** 在一个未排序的整数数组中,找到没有出现的最小的正整数。* 采用原地哈希/循环排序的方法。* @param nums 输入的整数数组* @return 缺失的最小正整数*/public int firstMissingPositive(int[] nums) {int n = nums.length;// 步骤 1: 原地重排数组,尝试将每个数字放到它正确的位置上。// 数字 x 应该在索引 x-1 的位置。for (int i = 0; i < n; i++) {// 当 nums[i] 在 [1, n] 范围内,并且它没有在正确的位置上时,循环交换。// 正确的位置是指:nums[i] 的值应该等于索引 nums[i]-1 上的值。// 例如,如果 nums[i] = 3,它应该在索引 2 的位置,即 nums[2] 的值应该是 3。while (nums[i] >= 1 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {// 将 nums[i] 与它目标位置上的数进行交换。int temp = nums[nums[i] - 1];nums[nums[i] - 1] = nums[i];nums[i] = temp;}}// 步骤 2: 查找第一个不满足 nums[i] == i + 1 的位置。for (int i = 0; i < n; i++) {// 如果在索引 i 上的值不是 i+1,那么 i+1 就是第一个缺失的正数。if (nums[i] != i + 1) {return i + 1;}}// 步骤 3: 如果 1 到 n 都存在,那么缺失的第一个正数就是 n+1。return n + 1;}
}

时空复杂度

时间复杂度:O(N)

  1. forwhile 循环:虽然代码中有一个嵌套的 while 循环,但它的总执行次数并不是 O(N^2)。
  2. 均摊分析
    • 关键在于,每一次 while 循环中的成功交换,都会将至少一个数字(即 nums[nums[i] - 1] 被换过来的那个)放到了它最终正确的位置上。
    • 一个数字一旦被放到正确的位置,它就不会再参与后续的交换了(因为 nums[i] == nums[nums[i] - 1] 条件会使其不满足 while 循环)。
    • 由于数组中只有 N 个位置,最多只会发生 N 次成功的交换。
    • 因此,所有 while 循环的总执行次数(包括成功的交换和不成功的检查)加起来是 O(N) 级别的。外层 for 循环也执行 N 次。所以这部分的复杂度是 O(N)
  3. 第二次遍历:最后的 for 循环遍历数组一次,时间复杂度为 O(N)

综合分析
算法的总时间复杂度是 O(N) + O(N) = O(N)

空间复杂度:O(1)

  1. 主要存储开销:该算法直接在输入数组 nums 上进行修改,没有创建任何与输入规模 N 成比例的新的数据结构。
  2. 辅助变量:只使用了 n, i, temp 等几个常数级别的整型变量。

综合分析
算法所需的额外辅助空间是常数级别的。因此,其空间复杂度为 O(1)。这是该问题最优的空间效率。

参考灵神

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

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

相关文章

C#上位机之Modbus通信协议!

文章目录前言一、Modbus概念二、使用步骤1.使用Modbus准备2.使用步骤三、Modbus RTU 与 Modbus ASCII对比前言 Modbus通信协议&#xff01; 一、Modbus概念 从站设备编码&#xff08;从站地址、单元ID&#xff09;&#xff0c;一主多从。 存储区&#xff1a;0-线圈状态、1-输…

前后端分离架构下的跨域问题与解决方案

在现代Web开发中&#xff0c;特别是随着前后端分离架构的普及&#xff0c;跨域问题成为了开发者必须面对的一个重要议题。本文将详细介绍什么是跨域问题、其产生的原因以及如何从前端和后端两个角度来解决这个问题&#xff0c;并提供一些实用的代码示例。一、跨域问题概述1. 定…

搜索数据建设系列之数据架构重构

导读 主要概述百度搜索业务数据建设的创新实践&#xff0c;重点围绕宽表模型设计、计算引擎优化和新一代业务服务交付模式&#xff08;图灵3.0开发模式&#xff09;三大方向&#xff0c;解决了传统数仓在搜索场景下面临的诸多挑战&#xff0c;实现了搜索数据建设的高效、稳定、…

2025年渗透测试面试题总结-2025年HW(护网面试) 29(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。、 目录 2025年HW(护网面试) 29 1. 样本分析思路 2. Linux GDB分析样本示例 3. 应急案例&#xff1a;WebShell后…

动态编程入门第二节:委托与事件 - Unity 开发者的高级回调与通信艺术

动态编程入门第一节&#xff1a;C# 反射 - Unity 开发者的超级工具箱 动态编程入门第二节&#xff1a;委托与事件 - Unity 开发者的高级回调与通信艺术 上次我们聊了 C# 反射&#xff0c;它让程序拥有了在运行时“看清自己”的能力。但光能看清还不够&#xff0c;我们还需要让…

降低网络安全中的人为风险:以人为本的路径

有效降低网络安全中的人为风险&#xff0c;关键在于采取以人为本的方法。这种方法的核心在于通过高效的培训和实践&#xff0c;使员工掌握安全知识、践行安全行为&#xff0c;并最终培育出安全且相互支持的文化氛围。 诚然&#xff0c;技术和政策必须为良好的安全行为提供支持、…

opencv裁剪和编译

opencv裁剪和编译 0. 准备工作 0.1 下载和安装Eigen 地址 https://eigen.tuxfamily.org/index.php?titleMain_Page对于opencv编译&#xff0c;需要增加EIGEN_INCLUDE_PATH和开启WITH_EIGEN -DWITH_EIGENON -DEIGEN_INCLUDE_PATH./3rd/eigen-3.4.01. 实际脚本 编译脚本如下: ch…

小白成长之路-mysql数据基础(三)

文章目录一、主从复制二、案例总结一、主从复制 1、master开启二进制日志记录2、slave开启IO进程&#xff0c;从master中读取二进制日志并写入slave的中继日志3、slave开启SQL进程&#xff0c;从中继日志中读取二进制日志并进行重放4、最终&#xff0c;达到slave与master中数据…

通过 Windows 共享文件夹 + 手机访问(SMB协议)如何实现

通过 Windows 共享文件夹 手机访问&#xff08;SMB协议&#xff09; 实现 PC 和安卓手机局域网文件共享&#xff0c;具体步骤如下&#xff1a; &#x1f4cc; 前置条件 电脑和手机连接同一局域网&#xff08;同一个Wi-Fi或路由器&#xff09;。关闭防火墙或放行SMB端口&#…

【Python3教程】Python3高级篇之正则表达式

博主介绍:✌全网粉丝23W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。 感兴趣的可…

Redis--黑马点评--达人探店功能实现详解

达人探店发布探店笔记探店笔记类似于点评网站的评价&#xff0c;往往是图文结合&#xff0c;对应的表有两个&#xff1a;tb_blog&#xff1a;探店笔记表&#xff0c;包含笔记中的标题、文字、图片等tb_blog_comments&#xff1a;其他用户对探店笔记的评价tb_blog表结构如下&…

一探 3D 互动展厅的神奇构造​

3D 互动展厅的神奇之处&#xff0c;离不开一系列先进技术的强力支撑 。其中&#xff0c;VR(虚拟现实)技术无疑是核心亮点之一。通过佩戴 VR 设备&#xff0c;观众仿佛被瞬间 “传送” 到一个全新的世界&#xff0c;能够全身心地沉浸其中&#xff0c;360 度无死角地观察周围的一…

C++ 网络编程(15) 利用asio协程搭建异步服务器

&#x1f680; [协程与异步服务器实战]&#xff1a;[C20协程原理与Boost.Asio异步服务器开发] &#x1f4c5; 更新时间&#xff1a;2025年07月05日 &#x1f3f7;️ 标签&#xff1a;C20 | 协程 | Boost.Asio | 异步编程 | 网络服务器 文章目录前言一、什么是协程&#xff1f;二…

【Java21】在spring boot中使用虚拟线程

文章目录 0.环境说明1.原理解析2.spring boot的方案3.注意事项&#xff08;施工中&#xff0c;欢迎补充&#xff09; 前置知识 虚拟线程VT&#xff08;Virtual Thread&#xff09; 0.环境说明 用于验证的版本&#xff1a; spring boot: 3.3.3jdk: OpenJDK 21.0.5 spring boot…

利器:NPM和YARN及其他

文章目录**1. 安装 Yarn&#xff08;推荐方法&#xff09;****2. 验证安装****3. 常见问题及解决方法****① 权限不足&#xff08;Error: EPERM&#xff09;****② 网络问题&#xff08;连接超时或下载失败&#xff09;****③ 环境变量未正确配置****4. 替代安装方法&#xff0…

跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能

众所周知&#xff0c;直播平台与短视频平台的贴纸功能不仅是用户表达个性的方式&#xff0c;更是平台提高用户粘性和互动转化的法宝。 可问题来了&#xff1a;如何让一个贴纸功能&#xff0c;在Android和iOS两大平台上表现一致、运行流畅、加载稳定&#xff1f;这背后&#xff…

JavaWeb(苍穹外卖)--学习笔记04(前端:HTML,CSS,JavaScript)

前言 本片文章是学习B站黑马程序员苍穹外卖的学习笔记。因为最近期末周&#xff0c;一直在应付考试所以就学的很少&#xff0c;恰好视频中在讲Nginx反向代理和负载均衡&#xff08;写着对前端的内容做一个复习&#xff09; 概述&#xff1a; 1.web前端主要由三部分组成&…

智能学号抽取系统 V5.4.3.2 —— Vue.js 实现的多功能课堂随机抽签工具

智能学号抽取系统 V5.4.3.2 —— Vue.js 实现的多功能课堂随机抽签工具 在教学或会议场景中&#xff0c;我们经常需要随机抽取一个或多个学号/编号来决定发言者、答题者或者参与者。为了提高效率和公平性&#xff0c;我们可以使用一些智能化的小工具来实现这一过程。 今天介绍…

从0开始学习R语言--Day39--Spearman 秩相关

在非参数统计中&#xff0c;不看数据的实际数值&#xff0c;单纯比较两组变量的值的排名是通用的基本方法&#xff0c;但在客观数据中&#xff0c;很多变量的关系都是非线性的&#xff0c;其他的方法不是对样本数据的大小和线性有要求&#xff0c;就是只能对比数据的差异性&…

WSL - Linux 安装 Anaconda3-2025.06-0 详细教程 [WSL 分发版均适用]

一、检查系统状态 安装前先确认 WSL - Linxu 已正常启动&#xff08;比如 Ubuntu&#xff09;&#xff0c;网络连接稳定&#xff0c;并且系统磁盘有足够空间&#xff0c;一般建议预留至少 5GB 以上的可用空间&#xff0c;避免因空间不足导致安装失败。 二、下载安装包 Anacond…