给定一个包含n+1个元素的整型数组,其中每一个元素都是一个1到n之间的正整数。该数组中存在唯一重复出现的数字,找出该数字。
比如:
Input: [1,3,4,2,2]
Output: 2
Input: [3,1,3,4,2]
Output: 3
算法要求:
- 不可改动数组
- 空间复杂度是
O(1)
- 时间复杂度必须低于$ O(n^2) $
根据这几个条件,我们可以首先放弃的方法就是排序以及map来计数统计的方法来解决这个方案。
如果按照各个数字分别统计的方法来进行统计的话,时间复杂度的要求不会得到满足。
由题意,可供使用的数字有n个,但是位置有n+1个,因此至少会有一个数字重复。 题干保证了只有唯一一个重复的数字。假设只重复了一次的话,那么就是将n个不同的数字均匀地分布到n+1个位置,剩下的那个位置放置重复的那个数字。也就是说,对于这n个数字的中间数x而言,必定会有小于x的数字数量和大于等于x的数字数量差一或者二。同理如果重复的数字的数量大于二,那么也是有一边多,一边少。而且数量多的那一边就是重复数字多的那一边。那么我们就可以通过二分法不断地缩小范围来找到多出来的那个数字。比如对于数组[1, 3, 4, 2, 2]
小于3的数有3个,大于2的数有2个,2 < 3
因此,重复的数字肯定是小于3的。小于2的数字有一个,大于1的数有2两个,因此重复的数字是2。
分情况。
假设寻找数字的范围是[left, right]
如果数字有奇数个,那么判断条件就是 $ x = count(>= mid) $ 和 $ y = count(<= mid)
如果数字有偶数个,那么判断条件就是$ x = count(> \lfloor mid \rfloor)
链表有一种表示方法就是通过数组来存储链表。因此我们可以把这个数组看作是一个链表。对于有重复数字的数组而言,就是该数组代表的链表里有一个环。那么就可以使用Floyd算法来解决。通过该方法找到的圆环的入口就是重复的数字。
设起点到圆环开始的距离是$ s