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:
1 | Input: [1,3,4,2,2] |
Example 2:
1 | Input: [3,1,3,4,2] |
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.
1 暴力法
我知道肯定会超时, 但是找出又满足不能modify数组的, 又要常数复杂度的, 又要小于n^2的实在做不到(流下了不学无术的泪水😭)
本来想用分治做的,但是没想出来(一直在想分为两个子数组之后如何在O(n)时间内找出两个子数组的重复元素?后来看答案发现这个思路错了)
1 | class Solution { |
2 分治
这个题用分治确实可以做, 但是不是将数组划分为两个子数组,而是将duplicate的元素所在的区间一步步划分。
假设low = 1, high = n, mid= (low + high)/2
现在统计各个段的元素个数,
1 | int cnt_smaller_than_mid = 0; |
如果等于mid的元素个数大于1,那么mid肯定是duplicate的
如果小于mid但大于等于low的元素个数 大于 mid - low,那么重复的元素肯定在[low,mid)中
如果大于mid但小于等于high的元素个数大于high - mid,那么重复的元素肯定在(mid,low]中,
再对[low,mid-1]或[mid + 1,low]采取相同的分治方法,最后求出答案,复杂度O(nlogn)
1 | class Solution { |
3 快慢指针
将这个数组看成一个链表, 第i个元素的下一个元素是位于nums[i]的元素.
例如 [1,3,4,2,2] 看作 1->3->2->4->2->4->2 …… 这个例子中, 有2个2, 即有2个指向元素4的指针. 4为环中第一个元素.
因为数组中存在重复的元素, 即两个值同时指向数组中的某个值. 所以, 这个链表中一定存在环. 类似于”6”这样的链表
利用快慢指针法 leetcode 142 即可找到环的起点.然后找到它的下标即可
不得不感叹想出这个方法的人的聪明, 完美的利用了0 < nums[i] < n的特点. 看样子同一个物种的🧠差距还是非常大的
1 | class Solution { |