问题描述

官网题目地址:

力扣​leetcode-cn.com

问题分析

典型的 “看起来很简单” 的题目,但再仔细看发现要求时间复杂度和空间复杂度要求就知道自己错了。

简单描述就是从 1~无穷大到所有整数中,对比输入的数,找到第一个缺失的即可。

首先最容易想到的应该就是 hash,因为把所有正整数往里面一丢,再一个一个查就可以了。但是题目要求不能有额外的空间开销。

如果使用hash map的,空间开销为 O(n),不符合题目要求为 O(1)。

解决方法

用一个数组当做hash map,因为数组中每个元素除了有实际数值,同时也有自己特有的下标,这个与map中的键值对是一样到。

对于输入数组nums与数组尺寸numsSize,首先需要证明两件事情:

  • 不需要考虑输入数据中的负数与0。因为需要找到没有出现的最小的正整数,所以很明显输入数据中的负数与0对输出结果没有影响。
  • 不需要考虑数组中大于或者等于 numsSize 的数。如果把缺失数据当成失误的话,那最完美的情况应该是从 1~numsSize 所有小朋友都到齐了。所以最大数为 numsSize;如果还存在负数、0或者大于numsSize 的数的话,说明从 1~numsSize 肯定存在缺席的小朋友。排排坐的道理很容易理解。

在证明了这两件事情之后,就可以放心的使用数组替代 map 或者 set 了。(数组下标不能为负数和大于 numsSize 的数)

接着需要思考如何使用数组作为map,比如说当输入数据为 [1, 3, 4, -1, 8] 的时候,循环的时候当遇到 1 时,对下标为 0 的数打个标记说这个小朋友到了,遇到 3 的时候把下标为 2 的数进行标记……因为 -1 为负数而 8 > numsSize 所以不必考虑。

最后标记完后,再循环一次,发现下标为 1 的没有被标记,所以第二个小朋友没来。

细节处理

如果输入数据为 [2, 1, 3, 5] 的时候,首先读到第一个数 2 的时候会对nums[1] 进行标记,但是继续往后面读,发现以前的 num[1] 被标记了,所以对于标记这个工作,既需要比较 a[1] 表示第二个数存在,又要保证接下来的访问读取不出错。所以需要定个规则,保证标记与原始数据信息都能存在。

这里采用的方法是添负号标记,求绝对值读取。

代码如下:

int firstMissingPositive(int* nums, int numsSize){// 1. 将负数变为 N+1,表示不在考虑范围内int i;for(i=0; i<numsSize; i++) {if(nums[i] <= 0) {nums[i] = numsSize + 1;}}// 2. 把出现过的数进行标记for(i=0; i<numsSize; i++) {// 防止前面的数标记了这个数导致下标为负数的错误int num = abs(nums[i]);if(num <= numsSize) {nums[num-1] = - abs(nums[num-1]);}}// 3. 找到没有标记的下标for(i=0; i<numsSize; i++) {if(nums[i] > 0) {return i+1;}}return numsSize+1;
}  

总结

两个亮点:

  • 使用数组替代map或者set。
  • 标记时保存了原始数据信息。

何言以对
2020.8.26 11:20

如何表示数组所有数都不等于一个数_力扣刷题那些事儿(3)-缺失的第一个正整数(41)...相关推荐

  1. 如何判断数组所有数都不等于一个数_【每日算法Day 91】求解数组中出现次数超过1/3的那个数

    题目链接 LeetCode 229. 求众数 II[1] 题目描述 给定一个大小为 的数组,找出其中所有出现超过 次的元素. 说明: 要求算法的时间复杂度为 ,空间复杂度为 . 示例1 输入: [3, ...

  2. 如何表示数组所有数都不等于一个数_每日算法系列【LeetCode 330】按要求补齐数组...

    题目描述 给定一个已排序的正整数数组 nums ,和一个正整数 n .从 [1, n] 区间内选取任意个数字补充到 nums 中,使得 [1, n] 区间内的任何数字都可以用 nums 中某几个数字的 ...

  3. 如何判断数组所有数都不等于一个数_工程师编程,C语言学习,关于数组方面的一些总结...

    在学习编程语言时,无论如何我们都逃不掉关于数组这个问题. 那么,在谈及这个问题时,我会从三个方面来思考: 1.数组的定义是什么,也就是何为数组? 2.如何在数组中填充元素(数据)? 3.如何用数组来解 ...

  4. 如何表示数组所有数都不等于一个数_每日算法系列【LeetCode 523】连续的子数组和...

    题目描述 给定一个包含非负数的数组和一个目标整数 k,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,总和为 k 的倍数,即总和为 n*k,其中 n 也是一个整数. 示例1 输入: [ ...

  5. 力扣刷题之合并两个有序数组

    力扣刷题之合并两个有序数组 题目 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目. 请你 合并 nu ...

  6. 力扣刷题pdf(java版本,内含暗黑版和光明版),都在这里了

    BAT大佬力扣刷题pdf,都在这里了! ​相信很多小伙伴刷题的时候面对力扣上近两千道题目,感觉无从下手! 我找了很久,今天终于让找到了Java版leetcode算法题解笔记,强烈建议先按照本篇介绍pd ...

  7. 力扣刷题笔记 数组篇02——双指针(快慢指针)法

    总结先放在前面: 双指针法在数组中是通过使用两个或者多个以上的下标,通过一个快指针和慢指针在一个for循环下完成两个for循环的工作,这样做大幅降低了时间复杂度 题目的类型也比较灵活,一般多用于有序数 ...

  8. <力扣刷题>442. 数组中重复的数据

    前言 人生如逆旅,我亦是行人.----苏轼<临江仙·送钱穆父> 题: 给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 ...

  9. [算法]力扣刷题-初级算法 - 数组(三)(数组篇完结) [两数之和] [有效的数独] [旋转图像]

    初级算法 - 数组篇完结: 初级算法 - 数组(一): https://blog.csdn.net/weixin_43854928/article/details/121315702 初级算法 - 数 ...

最新文章

  1. Codeforces Round #353 (Div. 2)
  2. ggplot2设置坐标轴范围_R可视化03|ggplot2图层-几何对象图层(geom layer)
  3. 图像语义分割:U-Net网络和PSP网络
  4. 数据库mysql中贴换函数_关于一个自定义MYSQL函数,实现点击链接后,在数据库里改变数据的问题。...
  5. Eclipse 插件用法:Eclipse 利用 Amateras UML 生成 Java 类图、时序图和 UML 类图
  6. 大数模拟——K - Large Division LightOJ - 1214
  7. OCRKit Pro for mac (OCR文字识别工具)
  8. c++自动抢购_小黄人汽车手机支架多功能出风口高档可充电全自动导航卡通支架2元优惠券券后价22.9元...
  9. 降维系列之 AutoEncoder 自动编码器
  10. java将doc转换成pdf_Java 将Word文档转换为PDF
  11. 自定义百度网盘分享密码 提取码
  12. Unity实现多语言切换
  13. Java项目:体育用品商城(java+SpringBoot+jsp+html+maven+mysql)
  14. macos 系统固件 路径_itunes下载固件在哪里 itunes下载固件位置【介绍】
  15. u深度重装系统详细教程_u深度u盘启动盘制作工具教程_u深度u盘装系统教程
  16. Spring学习笔记(五):JDBCTemplate+事务管理
  17. Oracle数据库文件
  18. 2015华为校园招聘机试题<一>
  19. 讲的真详细!如何成为一个更好的Android开发者?成功入职腾讯
  20. 这个 Chrome 插件,让你的 ChatGPT 不再报错

热门文章

  1. SSM-水果商城-项目展示-学习-1
  2. ansible安装与配置文件
  3. 顺势而为,戴尔加速流动文件系统进化
  4. 【转】暴露问题是对项目验收最起码的尊重!
  5. (一)开机demo测试及测试流程
  6. 计算机应用技术课程本科,《计算机应用技术I》课程教学大纲(共本科29级用)().doc...
  7. CSRF手工测试方法
  8. linux socket 模式,pythonsockets:如何在linux中启用混杂模式
  9. C++_012C++11的语法新特性
  10. Polylink 智能话机之—— e-talk 2200