278.寻找重复数
🕊︎ 278.寻找重复数
给定一个包含 n + 1
个整数的数组 nums
,其数字都在 [1, n]
范围内(包括 1
和 n
),可知至少存在一个重复的整数。
假设 nums
只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums
且只用常量级 O(1)
的额外空间。
思路
基本思想
题目中说,一共有n+1
个数,但是数字的范围为[1,n]
。这是典型的鸽巢原理的题目,即使每个数字只出现一次,那么最后一定会多一个元素,这个元素就是重复的。这是最极端的情况,真实情况下,重复的元素可能不止重复一次,但是题目中又描述,只有一个重复的元素,说明就是这种最极端的情况
为了找到这个重复的元素,可以借鉴 环形链表II 的思想,先找到环,之后找到环的入口,这个入口就是重复的元素,为了找到环,需要使用快慢指针的思想。为了找到入口,需要从链表的起点和当前相遇的点开始向后走,二者再次相遇的地方就是环的入口,这是经过环形链表II中推导得到的。
但是上面的思想是链表中,本题中提供的是数组,所以需要将数组转换成链表,于是可以利用下标index
和数值nums[index]
之间的映射关系来构造一个链表
由于一共有n+1
个数,所以数组元素下标的范围为[0~n]
,而数组中的每一个元素的范围为[1~n]
,这可以说明,可以直接建立映射,不用担心建立应设置后数组下标越界的情况
所以第一阶段就是判断环在哪
|
|
因为必须要先走一步,所以可以将while循环改成do while循环
|
|
上面代码中的快慢指针移动的方式需要注意,slow = nums[slow]
代表慢指针走了一步。fast = nums[nums[fast]]
代表快指针走了两步。当退出循环的时候,就是找到环的时候,此时需要将环的入口找到
找入口的代码就是一个指针从起点出发,一个指针从相遇点出发,按照相同的步伐向后走。再次相遇就找到了环的入口,这个地方就是重复元素出现的位置
核心就是将数组转换成链表,利用了
index
和nums[index]
之间的映射关系
执行流程
- 利用下标和元素之间的映射关系将数组转换成链表,然后利用快慢指针找到环
- 一个指针从起点出发,一个指针从相遇点出发,按照相同的步伐找到环的入口
- 返回入口元素就是重复的元素
代码
根据以上分析,得出以下代码:
|
|
总结
重点或者说巧妙地地方就是将数组转换成链表,利用了下标和元素之间的对应关系,由于存在鸽巢原理的情况,所以一定有一个重复元素,并且按照题意只有唯一一个重复元素,利用环形链表II的思想,找到环之后,环的入口处就是重复元素,也就是最终的答案
- 数组转换成链表
- 找到环的入口
- 返回结果