力扣-287-寻找重复数
感觉跟《剑指Offer》-50-第一个只出现一次的字符,有点神似
数组中只有一个数组会重复(可能不止两次),找出这个数字
如果用set,这是非常简单的,比两数之和还简单,所以题目要求空间复杂度O(1)
如果排个序,这题也会比较简单,只要检查有没有相邻且相等的元素,所以题目要求不能修改数组
O(n^2^)
去挨个找肯定也不合适
我想到了数组下标一一对应,不过那也需要移动元素
我想到了数组和,它是个定值,等于1+2+3+…+n
,拿这个和去减数组和,然后求绝对值
不行啊,这样只能得到被替换数字和重复数字的差值,条件不够
瞄了一眼题解,思路是这样,如果将数组元素的下标看作一个指针映射,那么可以把数组变成一个带环的链表,那么这题可能就变成了环形链表
能这么做也是因为题目特性,范围1-n且除重复元素外只出现一次
建立映射,从下标i=0开始,指向,同时nums[i]作为新的下标
那么直接将nums[i]作为下标,如果nums[i]==n怎么办?没有下标n
好吧,注意理解题目,如果数字数量是n,那么数组中最大的数字是n-1
听起来有点怪怪的,按理说1到1+n的数组中应该有n+1个整数才对,且最大数为n+1,但这里最大数为n,也就是说n+1被一个重复数字替代了
如果是这样,上面的映射便能够成立,不会越界
从i=0开始,nums[i]指向nums[nums[i]],以此循环
发现看不懂自己前两天写的环形链表Ⅱ的题解,而且是有问题的
首先可以确定的是,路径存在环的话,快慢指针一定会相遇,这个没有疑问,在环中满指针一定会追上
再说,当满指针第一次进入环,落在起始节点时,快指针一定已经在环中了,这也是没有问题的
这时他俩的距离一定是>=0且<环的长度的,这也是确定的
那么因为每移动一步,他俩距离就会缩小1,所以直到被追上,他俩移动的距离不会超过他俩的距离即小于环的长度大于等于0
也就是说满指针跑不完一个环,即不会跑完整个路径
那么我们知道了,满指针会在第一次遍历路径的过程中,跑不完一圈循环就会被追上
假设外段长a,循环段长b,慢指针在循环段中跑了c被追上
被追上时,慢指针走了a+c步,则快指针是他的两倍2(a+c)
同时快指针走了a+nb+c
等式nb=a+c
变形,a=(n-1)b+b-c
就是另外用一个指针从头跑a步到环的入口节点,同步已经相遇的快慢节点一起跑的话,快慢节点会在跑了b-c也就是一圈没跑完的剩余长度和n-1圈之后,和另外的指针在头节点相遇
回到本题,nums[i]>1结合上面的最大值分析,可以说这样的映射不会出现越界问题
int fast = nums[0], slow = nums[0], another = nums[0]; while (fast != slow) { fast = nums[fast]; fast = nums[fast]; slow = nums[slow]; }
写的时候,这里的初始化有点麻烦,直接加上||fast==nums[0]
当第一个节点就是目标的时候会出现死循环的情况
这里的初始化条件又恰好满足了循退出条件
int findDuplicate(vector<int>& nums) { int fast = nums[0], slow = nums[0], another = nums[0]; while (true) { fast = nums[fast]; fast = nums[fast]; slow = nums[slow]; if (fast == slow) break; } while (another != fast) { another = nums[another]; fast = nums[fast]; } return another; }
改成这样,第二个循环不存在这个问题
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16855616.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步