LeetCode:287. Find the Duplicate Number
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
Example 1:
Input: [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2]
Output: 3
找到数组中重复多次的那个数(唯一)。
思路一:元素值作索引
从位置0开始遍历数组,每次得到的元素值作为下一个遍历的元素,并且将遍历过的元素置为0,如果存在重复的元素值,那么这个位置的元素肯定会被多次访问,如果访问到的元素值为0则表明这个下标已经被访问过了,也就是要找的重复元素。
class Solution:
def findDuplicate(self, nums):
l = len(nums)
index = 0
while(nums[index] != 0):
tmp = nums[index]
nums[index] = 0
index = tmp
if (nums[tmp] == 0):
return tmp
思路二:快慢指针
官方还提供了一个叫 Floyd's Tortoise and Hare (Cycle Detection)
的算法。核心思想是用两个指针检测数组访问次序中存在的环形链表。
Python 实现代码
class Solution:
def findDuplicate(self, nums):
# Find the intersection point of the two runners.
tortoise = nums[0]
hare = nums[0]
while True:
tortoise = nums[tortoise]
hare = nums[nums[hare]]
if tortoise == hare:
break
print(tortoise,hare)
return tortoise
# Find the "entrance" to the cycle.
ptr1 = nums[0]
ptr2 = tortoise
while ptr1 != ptr2:
ptr1 = nums[ptr1]
ptr2 = nums[ptr2]
return ptr1
同样是以当前元素值作为下次访问的下标,首先是快慢指针都从0位置出发,慢指针每次移动一个元素,快指针每次移动两个元素。因为存在重复元素,所以这种遍历方法肯定会存在一个环形遍历次序,两个指针也会最终访问重叠。可以按照下面的具体步骤找到环入口:
- 设:slow指针移动速度为1,fast指针移动速度为2;如果slow指针在链表的非环部分(也就上面图中的前面四个节点部分)移动的长度为a,slow指针在环内移动长度为b;
- 两指针相遇时候记为C点(不是环入口),slow指针移动距离为a+b,fast指针移动距离为2(a+b),可知两指针距离差
a+b即为整数倍的环长
; 从head开始移动a的距离为入环点
(环入口),由2可知从head开始移动a+(a+b)的距离也为入环点
,即从C点开始继续移动距离a则可到达入环点
;- 再将slow指针移动回head处,同时同速移动两个指针,相遇点即为入环点。
THE END.