题目描述:
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
解题思路:
1、利用排序:
这道题很容易想到的思路是使用排序算法得到一个排序的数组,然后顺序判断每一个数字,如果存在重复的数字,则该数字一定是连续的,这样就可以找出重复的数字,但是由于排序算法的时间复杂度是O(nlogn),因此这个算法不是最优的。
2、哈希表:
同时也可以利用哈希表来解决这个问题,也就是从头顺序扫描数组,每扫描一个数字时都可以使用O(1)的时间复杂度判断哈希表中是否已经包含了该数字,如果没有的话则保存该数字到哈希表中,否则该数字就是重复数字。这种算法的时间复杂度为O(n),但是空间复杂度是O(n),因为需要一个空间大小为O(n)的哈希表。
3、最优算法:
由于题目描述中该数组nums是一个大小为n,同时数字范围为0~n,因此可以利用这个特性来进行扫描,扫描的方法是:从头开始扫描数组,判断每个数字nums[i]和nums[nums[i]]中是否一样,如果一样,则num[i]是重复数字;否则交换这两个数字,即swap(nums[i],nums[nums[i]]),然后继续判断下一个数字,即nums[i](nums[i]已经是交换后的数字了,也就是下一个数字),使用这种方法可以遍历整个数组,同时空间复杂度为O(1),由于每个数字最多交换两次,因此时间复杂度为O(n)。
实现代码:
//返回数组中任意一个重复的数字
public int findRepeatNumber(int[] nums) {
if(nums == null || nums.length == 0)
return -1;
for(int i = 0; i < nums.length; i++){
while(nums[i] != i){//只要下标不对应才判断
if(nums[i] == nums[nums[i]])//判断是否重复
return nums[i];
else
swap(nums, i, nums[i]);//交换nums[i]和nums[nums[i]]
}
}
return -1;
}
public void swap(int a[],int i, int j){
int t = a[j];
a[j] = a[i];
a[i] = t;
}
本文介绍了一种在0~n-1范围内寻找数组中重复数字的最优算法,通过巧妙利用数组特性和原地交换,实现了O(n)时间复杂度和O(1)空间复杂度的解决方案。
324

被折叠的 条评论
为什么被折叠?



