当前位置: 首页 > news >正文

【寻找重复数字】——脑筋急转弯...

寻找重复数字

287. 寻找重复数

题目难度

中等

相关标签与企业信息

[相关标签]
[相关企业]

题目描述

给定一个包含 n + 1 n + 1 n+1 个整数的数组 nums,其数字都在 [ 1 , n ] [1, n] [1,n] 范围内(包括 1 1 1 n n n),可知至少存在一个重复的整数。

假设 nums 只有一个重复的整数,返回这个重复的数。

你设计的解决方案必须不修改数组 nums 且只用常量级 O ( 1 ) O(1) O(1) 的额外空间。

示例

示例1

输入nums = [1, 3, 4, 2, 2]
输出2

示例2

输入nums = [3, 1, 3, 4, 2]
输出3

示例3

输入nums = [3, 3, 3, 3, 3]
输出3

提示信息

  • 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105
  • nums.length == n + 1
  • 1 ≤ n u m s [ i ] ≤ n 1 \leq nums[i] \leq n 1nums[i]n
  • nums 中只有一个整数出现两次或多次,其余整数均只出现一次。

进阶问题

如何证明 nums 中至少存在一个重复的数字?

根据抽屉原理(鸽巢原理),将 n + 1 n + 1 n+1 个元素放到 n n n 个集合中,那么至少有一个集合里面会有两个或更多的元素。

在本题中,数组 nums n + 1 n + 1 n+1 个整数,而这些整数的取值范围是 [ 1 , n ] [1, n] [1,n],相当于把 n + 1 n + 1 n+1 个“鸽子”放进 n n n 个“鸽巢”(数字 1 1 1 n n n 所代表的 n n n 个区间),所以必然至少存在一个数字是重复的。

比如一个训练营里面有367人,则必然至少有 两个人生日同一天。

你可以设计一个线性级时间复杂度 O ( n ) O(n) O(n) 的解决方案吗?

解题思路

方法一:快慢指针(类似环形链表找环入口)

  • 把数组 nums 中的值看作是下一个节点的索引,这样整个数组就可以看作是一个类似链表的结构。
  • 由于存在重复的数字,那么必然会形成一个“环”,因为从某个重复数字开始,会再次指向已经访问过的节点(也就是这个重复数字本身对应的下一个节点)。
  • 我们可以使用快慢指针的方法来找到这个环的入口,也就是重复的数字。
  • 复习链表找环
  • 这个也太难想到了吧,没想到这里遇到了环形链表!!

该思路主要是通过将数组视为特殊链表结构来解决寻找重复数的问题,具体如下:

整体思路转化

把给定的数组 nums 中的值当作指向下一个链表节点的索引,从而将寻找数组中重复数字的问题转化为在类似链表结构中寻找环的起点的问题,因为存在重复数字时会形成环。

快慢指针运用

  • 初始化:设置 slow 指针指向数组第一个节点(nums[0]),fast 指针指向第二个节点(nums[nums[0]])。
  • 找环过程:通过循环让快慢指针移动,slow 每次按当前节点值作为索引移动一步,fast 每次先根据当前节点值作为索引找到下一个节点,再以该节点值作为索引移动两步。由于 fast 速度是 slow 的两倍,在有环情况下它们必然会在环内相遇。
  • 确定重复数:当快慢指针相遇后,设置一个新指针(如代码中的 pre)从链表起点出发,与在环内相遇的 slow 指针同步移动,每次按节点值作为索引前进。由于从链表起点到环入口的距离和从相遇点到环入口的距离相等,所以它们再次相遇的点就是环的入口,即数组中的重复数字。
class Solution:def findDuplicate(self, nums: List[int]) -> int:# 将该数组视为链表,数组上的值视为指向下一个链表节点的索引# 将“寻找数组重复数”的问题转变成了“寻找链表环的起点(已经解决)”# 寻找链表环起点: ## 快慢指针找环## 若相遇,f走了2x,s走了x;假设s在环内走了t,环外链表长x-t,## 此时 head走x-t到入口,s走x-t也回到入口# 初始化快慢指针:slow 第一个节点,fast 第二个节点[第一个节点值作为索引]slow, fast = nums[0], nums[nums[0]]# 判断有无环,while逻辑:没走到终点就一直走# while nums[slow] and !!!这道题不需要判断,默认输入必有环# 所以直接开始找环# 第一次进入环:while slow != fast:slow = nums[slow]fast = nums[nums[fast]]# 退出以上while的条件是实现了s和f指针的第一次相遇# 此时将其中一个指针退回到起点,或者设置一个起点指针pre = 0# 设置pre和s同步走,相遇点就是环入口,就是重复数while pre != slow:slow = nums[slow]pre = nums[pre]return slow

以下是对上述用于寻找数组重复数的代码的时空复杂度分析:

时间复杂度

  • 整体分析思路:时间复杂度主要取决于代码中循环语句的执行次数。在这段代码中,有两个主要的 while 循环,我们分别来分析它们对时间复杂度的影响。

  • 第一个 while 循环(快慢指针找环)

    • 在这个循环中,slow 指针和 fast 指针在类似链表的结构中移动,直到它们相遇。由于 fast 指针每次移动的速度是 slow 指针的两倍,所以在最坏的情况下,fast 指针需要绕环两圈才能和 slow 指针相遇(可以想象成在一个环形跑道上,快跑的人要追上慢跑的人,最多跑两圈就能追上)。
    • 而对于整个数组 nums 所构成的类似链表结构,其长度为 n + 1(题目中给定数组包含 n + 1 个整数)。即使在最坏的情况下,fast 指针绕环两圈,它总共走过的节点数也不会超过数组长度的两倍,也就是 O(2(n + 1)),根据大O表示法的特性,常系数可以忽略,所以这个循环的时间复杂度为 O(n),其中 n 是数组 nums 的长度(准确来说是 n + 1,但在大O表示法中可以近似看作 n)。
  • 第二个 while (确定环入口即重复数)

    • 当快慢指针相遇后,新设置的指针(如代码中的 pre)和在环内相遇的 slow 指针同步移动,直到它们再次相遇找到环的入口,也就是重复的数字。在这个过程中,这两个指针最多需要遍历整个数组长度的节点数,因为从它们开始同步移动到相遇,所走过的路径长度不会超过数组所构成的类似链表结构的总长度。
    • 所以这个循环的时间复杂度同样为 O(n),其中 n 是数组 nums 的长度。
  • 综合时间复杂度:由于整个代码的执行时间主要由这两个 while 循环决定,并且它们的时间复杂度都是 O(n),所以这段代码的总体时间复杂度为 O(n)

空间复杂度

  • 分析思路:空间复杂度主要看代码在执行过程中额外开辟的空间大小,与输入数据的规模无关。

  • 代码中的空间使用情况:在这段代码中,除了定义了几个指针变量(如 slowfastpre)来辅助完成算法逻辑外,并没有使用额外的数据结构来存储数据。这些指针变量所占用的空间是固定的,不随输入数组的长度 n 而变化。

  • 空间复杂度结论:所以,根据空间复杂度的定义,这段代码的空间复杂度为 O(1),即只使用了常量级别的额外空间,满足题目要求不使用超过常量级 O(1) 的额外空间来解决问题。

综上所述,这段代码的时间复杂度为 O(n),空间复杂度为 O(1)

方法二:二分查找

为什么可以通过 mid(中间值)和 count(小于等于中间值的数字个数)的大小关系来判断重复数字所在的区间。

整体思路

我们的目标是在数组 nums 中找到那个重复的数字,已知数组中的数字范围是 [1, n],且只有一个数字是重复的。我们通过不断二分这个范围 [1, n],并根据 countmid 的关系来逐步缩小重复数字可能存在的区间。

具体解释

假设当前我们正在考虑的范围是 [left, right](在代码中最初就是 [1, len(nums) - 1],随着循环不断更新 leftright),然后我们计算出了这个区间的中间值 mid

接下来我们统计数组 nums 中小于等于 mid 的数字个数,记为 count

  • count > mid

    • 正常情况下,如果数组中的数字没有重复,那么在范围 [1, mid] 内的数字应该恰好出现 mid 次(因为每个数字只出现一次嘛)。
    • 但现在我们统计出来的 count 大于 mid,这就意味着在 [1, mid] 这个区间内的数字出现的次数比正常情况多了。为什么会多呢?只能是因为那个重复的数字在这个区间内呀,所以重复的数字肯定在 [1, mid] 这个区间,我们就可以把查找范围的上界 right 更新为 mid,下一次就在缩小后的范围 [1, mid] 内继续查找。
  • count <= mid

    • 同样,如果数字没有重复,在范围 [1, mid] 内的数字应该恰好出现 mid 次。
    • 现在 count 不大于 mid,说明在 [1, mid] 这个区间内的数字出现的次数是正常的或者更少,那就意味着重复的数字不在这个区间内,而是在 [mid + 1, right] 这个区间里,所以我们就把查找范围的下界 left 更新为 mid + 1,下一次就在缩小后的范围 [mid + 1, right] 内继续查找。

通过这样不断地根据 countmid 的关系来更新查找范围,最终就能确定重复数字所在的区间,当查找范围缩小到只剩下一个数字时,这个数字就是我们要找的重复数字啦。

例如,假设有数组 [3, 1, 3, 4, 2],我们来模拟一下这个过程:

  • 初始时,left = 1right = 4(因为数组长度是 5,数字范围是 [1, 4]),计算出 mid = 2
  • 统计数组中小于等于 2 的数字个数 count,发现有 2 个(12),此时 count <= mid,说明重复数字不在 [1, 2] 区间,我们就把 left 更新为 3
  • 下一次循环,left = 3right = 4,计算出 mid = 3,再统计小于等于 3 的数字个数,发现有 3 个(312),此时 count > mid,说明重复数字在 [1, 3] 区间,我们就把 right 更新为 3
  • 此时 left = right = 3,所以重复数字就是 3

希望这样解释能让你清楚理解 midcount 的关系以及为什么可以通过它们来判断重复数字的位置。

!最关键的一步是:mid与count的比较!照理来说,count就是该比mid小!
只要大了,就在这个范围内!

方法二:二分查找

def findDuplicate(nums):low = 1high = len(nums) - 1while low < high:mid = low + (high - low) // 2count = 0for num in nums:if num <= mid:count += 1if count > mid:high = midelse:low = mid + 1return low

测试用例

测试用例1

输入nums = [1, 3, 4, 2, 2]
预期输出2

测试用例2

输入nums = [3, 1, 3, 4, 2]
预期输出3

测试用例3

输入nums = [3, 3, 3, 3, 3]
预期输出3

测试用例4

输入nums = [1, 2, 3, 4, 4]
预期输出4

测试用例5

输入nums = [2, 2, 2, 2, 2]
预期输出2

测试结果

方法一:快慢指针

  • 测试用例1:通过,输出为2
  • 测试用例2:通过,输出为3
  • 测试用例3:通过,输出为3
  • 测试用例4:通过,输出为4
  • 测试用例5:通过,输出为2

方法二:二分查找

  • 测试用例1:通过,输出为2
  • 测试用例2:通过,输出为3。。
  • 测试用例3:通过,输出为3
  • 测试用例4:通过,输出为4
  • 测试用例5:通过,输出为2

通过对多种测试用例的测试,两种方法都能正确地找出数组中重复的数字,满足题目要求。

相关文章:

【寻找重复数字】——脑筋急转弯...

寻找重复数字 287. 寻找重复数 题目难度 中等 相关标签与企业信息 [相关标签] [相关企业] 题目描述 给定一个包含 n 1 n 1 n1 个整数的数组 nums&#xff0c;其数字都在 [ 1 , n ] [1, n] [1,n] 范围内&#xff08;包括 1 1 1 和 n n n&#xff09;&#xff0c;可…...

AI基础知识

目录 1.激活函数:one: 激活函数的作用:two: sigmoid函数:three: tanh函数:four: ReLu:five: Leaky ReLU 2.Softmax函数3.优化器:one: 优化器的作用:two: BGD&#xff08;批梯度下降&#xff09;:three: SGD&#xff08;随机梯度下降&#xff09;:four: MBGD&#xff08;Mini Ba…...

ubuntu 22.04 硬件配置 查看 显卡

ubuntu 22.04 硬件配置 查看 显卡 1. 参考文档 ubuntu 安装 nvidia 驱动 https://blog.51cto.com/u_13628828/7056095 input: HDA NVidia HDMI/DP,pcm3 as /devices/pci0000:00/0000:00:01.0/0000:01:00.1/sound/card1/input11 input: HDA NVidia HDMI/DP,pcm7 as /devices/…...

【计算机网络】网络框架

一、网络协议和分层 1.理解协议 什么是协议&#xff1f;实际上就是约定。如果用计算机语言进行表达&#xff0c;那就是计算机协议。 2.理解分层 分层是软件设计方面的优势&#xff08;低耦合&#xff09;&#xff1b;每一层都要解决特定的问题 TCP/IP四层模型和OSI七层模型…...

linux nvidia/cuda安装

1.查看显卡型号 lspci |grep -i vga2.nvidia安装 2.1在线安装 终端输入&#xff08;当显卡插上之后&#xff0c;系统会有推荐的安装版本&#xff09; ubuntu-drivers devices可得到如下内容 vendor : NVIDIA Corporation model : TU104GL [Tesla T4] driver : nvid…...

硬件设备网络安全问题与潜在漏洞分析及渗透测试应用

以下笔记学习来自B站泷羽Sec&#xff1a; B站泷羽Sec 一、硬件设备的网络安全问题点 1.1 物理安全问题 设备被盗或损坏渗透测试视角 攻击者可能会物理接近硬件设备&#xff0c;尝试窃取设备或破坏其物理结构。例如&#xff0c;通过撬锁、 伪装成维修人员等方式进入设备存放…...

#渗透测试#SRC漏洞挖掘#CSRF漏洞的防御

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…...

C++ | Leetcode C++题解之第542题01矩阵

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {int m matrix.size(), n matrix[0].size();// 初始化动态规划的数组&#xff0c;所有的距离值都设置为一个很大的…...

RabbitMQ 不公平分发介绍

RabbitMQ 是一个流行的开源消息代理软件&#xff0c;它实现了高级消息队列协议&#xff08;AMQP&#xff09;。在 RabbitMQ 中&#xff0c;消息分发策略对于系统的性能和负载均衡至关重要。默认情况下&#xff0c;RabbitMQ 使用公平分发&#xff08;Fair Dispatch&#xff09;策…...

测试实项中的偶必现难测bug--一键登录失败

问题描述:安卓和ios有出现部分一键登录失败的场景,由于场景比较极端,衍生了很多不好评估的情况。 产生原因分析: 目前有解决过多次这种行为的问题,每次的产生原因都有所不同,这边根据我个人测试和收集复现的情况列举一些我碰到的: 1、由于我们调用的是友盟的一键登录的…...

危!这些高危端口再不知道问题就大了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 端口作为网络通信的基本单元&#xff0c;用于标识网络服务和应用程序。 但某些端口由于其开放性和易受攻击的…...

Redis集群模式之Redis Sentinel vs. Redis Cluster

在分布式系统环境中&#xff0c;Redis以其高性能、低延迟和丰富的数据结构而广受青睐。随着数据量的增长和访问需求的增加&#xff0c;单一Redis实例往往难以满足高可用性和扩展性的要求。为此&#xff0c;Redis提供了两种主要的集群模式&#xff1a;Redis Sentinel和Redis Clu…...

Leetcode 罗马数字转整数

代码的算法思想可以分为以下几步&#xff1a; 建立映射表&#xff1a; 首先&#xff0c;代码使用 HashMap 来存储罗马数字字符与其对应的整数值关系。例如&#xff0c;I 对应 1&#xff0c;V 对应 5&#xff0c;以此类推。这是为了方便后续快速查找每个罗马字符对应的整数值。 …...

东方通TongWeb替换Tomcat的踩坑记录

一、背景 由于信创需要&#xff0c;原来项目的用到的一些中间件、软件都要逐步替换为国产品牌&#xff0c;决定先从web容器入手&#xff0c;将Tomcat替换掉。在网上搜了一些资料&#xff0c;结合项目当前情况&#xff0c;考虑在金蝶AAS和东方通TongWeb里面选择&#xff0c;后又…...

ceph介绍和搭建

1 为什么要使用ceph存储 什么是对象存储&#xff1f; 对象存储并没有向文件系统那样划分为元数据区域和数据区域&#xff0c;而是按照不同的对象进行存储&#xff0c;而且每个对象内部维护着元数据和数据区域。因此每个对象都有自己独立的管理格式。 对象存储优点&#xff1a…...

树莓派安装FreeSWITCH

1、下载相关资源&#xff1a; # 假设所有资源都下载到/opt/目录下 cd /opt # 下载FreeSWITCH源码 git clone https://github.com/signalwire/freeswitch # 下载libks源码 git clone https://github.com/signalwire/libks # 下载sofia-sip源码 git clone https://github.com/fr…...

OpenSSL 生成根证书、中间证书和网站证书

OpenSSL 生成根证书、中间证书和网站证书 一、生成根证书&#xff08;ChinaRootCA&#xff09;二、生成中间 CA&#xff08;GuangDongCA&#xff09;三、生成网站证书&#xff08;gdzwfw&#xff09; 一、生成根证书&#xff08;ChinaRootCA&#xff09; 创建私钥&#xff1a; …...

MySQL核心业务大表归档过程

记录一下2年前的MySQL大表的归档&#xff0c;当时刚到公司&#xff0c;发现MySQL的业务核心库&#xff0c;超过亿条的有7张表&#xff0c;最大的表有9亿多条&#xff0c;有37张表超过5百万条&#xff0c;部分表行数如下&#xff1a; 在测试的MySQL环境 &#xff1a; pt-archiv…...

dapp获取钱包地址,及签名

npm install ethersimport {ethers} from ethers const accounts await ethereum.request({method: eth_requestAccounts}); // 获取钱包地址 this.form.address accounts[0] console.log("accounts:" this.address)const provider new ethers.BrowserProvider(…...

探索Dijkstra算法的普遍最优性:从经典算法到最新学术突破

引言 在计算机科学中&#xff0c;Dijkstra算法是解决单源最短路径问题的经典算法&#xff0c;尤其在地图导航、网络通信和机器人路径规划等领域有着广泛应用。近期&#xff0c;学术界在此算法上取得了重大突破&#xff1a;研究人员证明了Dijkstra算法的“普遍最优性”&#xff…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...