题目
找出数组中重复的数字。
在一个长度为 n 的数组
nums
里的所有数字都在0~n-1
的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。示例 1:
1
2
3 输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3限制:
2 <= n <= 100000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
审题
题目是找出任意一个重复数字,意味着我们找到就可以返回了。
解题
很明显可以利用unordered set
来解决。
这里复习一下unordered_set
的插入操作:
1 | unordered_set<int> lookup; |
代码如下:
1 | class Solution { |
- 时间复杂度O(N)
- 空间复杂度O(N)
但是测试用例执行用时112ms,所以肯定需要优化。
优化
下面用 vector 代替散列表试试看。
1 | class Solution { |
时间有提升,但变化不大。
变式
如果要求空间复杂度为O(1)呢?
那么我们就必须在原地进行操作。
由于给定了值域和个数,如果没有重复,那么从 0 到 n-1 应该是一个萝卜一个坑。
一种简单的思路是原地排序,然后扫描数组,返回第一个错位的数,但是用快排都已经需要O(NlogN)的时间复杂度了。
仔细思考发现我们并不需要对整个数组排序,只要找到第一个“位置被占”的数字就可以了。
1 | for(int i=0; i<nums.size(); ++i) { |
代码:
1 | class Solution { |
- 时间复杂度,最坏情况为没有重复数字,此时把所有数字归位需要O(N)
进阶
如果需要在不破坏数组的基础上找到重复数字呢?
对于数组[0,1,…,n−1],任意取一个数m,如果整个数组无重复数字,那么小于m的数一定有m个,否则一定有重复数字,接下来就是二分查找。时间复杂度O(NlogN),空间复杂度O(1)。