问题描述:
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.
Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than
O(n2)
.
There is only one duplicate number in the array, but it could be repeated more than once.
问题来源:
Find the Duplicate Number (具体地址:https://leetcode.com/problems/find-the-duplicate-number/#/description)
思路:在这就给出最好的解法了,其他的二分查找啥的就不介绍了哈。这道题首先它的原理是组合数学当中非常著名的
鸽巢原理,也叫抽屉原理鸽巢原理。有n + 1个数,但是只包含1~n之间的数,所以必然会有一个数字是重复的。现在我们该怎么找出它呢?这道题如果第一次见,还是挺难想到的,
我们可以定义两个指针,一个定义为fast,它每次走两步,而另一个指针定义为slow,它每次走一步。下面举个例子来说明一下具体两个指针咋走的:
index(数组索引)i:0 1 2 3 4 5 6 7 8
具体数值nums[i]:2 3 5 6 1 7 8 1 4
在这假定1是重复的,正确走的每一步规则是i = nums[i],所以正确的走法为:2->5->7->1->3->6->8->4->1->...,然后就开始循环了,所以快指针fast走的是2->7->3->8->1>3->8....,慢指针slow走的就是上面的一步一步的走的,就不在这列了。所以这样下去,
一定会在环中的某个点上相遇的 ,具体可以参考
cycle detection或者叫做cycle finding,然而我们要求的不是这个结果,我们要求的是重复的数字,也就是这个例子当中的1,即环的入口。
如何求环的入口:
上面咱们不是已经求出它们再环中相遇的位置了嘛,保留一个指针slow或者fast都可以,然后让其中一个(在这我采用的是finder)从数组的开始位置开始走,此时留在环中的指针同时走,而且这次咱们都走一步,最后再次相遇的时候找到的就是环的入口。
具体有些人直接懵逼了,觉得你说咋相遇就相遇了呢?给出我画的一个简易版的图
代码:
体会:这道题还是很有意义的,第一次见到的话还是比较难想到这种解法的。