剑指 Offer 03. 数组中重复的数字
剑指 Offer 03. 数组中重复的数字
一 找出数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
题解
-
解一:将数组排序后再遍历,需要时间复杂度O(nlogn),空间复杂度O(1)
-
解二:使用哈希表,再遍历数组时判断哈希表中是否包含该数(O(1)),如果包含则找到重复数,如果不包含则把该数字加入哈希表。
时间复杂度和空间复杂度都是O(n)
- 解三:因为输入的数字在0~n-1之间,所以可以在原数组上建立数字与下标的对应关系
- 遍历数组,如果nums[i]=i,则i++判断下一个
- 如果nums[i]不等于i,则记nums[i]为m,将数字m和在第m位上的数比较
- 如果m=nums[m]则找到重复数
- 否则将nums[m]与nums[i]交换
- 虽然有嵌套的循环,但每循环一次就会有一个数字回到原位或得出结果,所以时间复杂度是O(n)
- 空间复杂度O(1)
class Solution {
public int findRepeatNumber(int[] nums) {
int res=-1;
for(int i=0;i<nums.length;i++){
while(nums[i]!=i){
int current=nums[i];
if(nums[current]==current){
return current;
}else {
nums[i]=nums[current];
nums[current]=current;
}
}
}
return res;
}
}
二 不修改数组找出重复数
在一个长度为n + 1的数组里面的所有数字都在1 ~ n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应输出的重复数字应该是2或者3。
与题一类似,但要求不修改原数组,所以不能使用解一和解三,解二的话需要O(n)的空间复杂度,如果要求必须使用O(1)空间复杂度的算法呢?
- 注意到题目要求:数组长度为n+1,而存的数字大小在1~n的范围内,所以说在这1~n的n个数中必定至少有一个数是重复的,所以可以考虑使用二分的思想。
- 记1~n中间的数字为m,统计1~m中数字在数组中出现的次数,如果次数超过m,则说明重复数字大小在1~m的范围内,否则在m+1~n内
时间复杂度:二分查找的时间复杂度为O(logn),因为每一次二分完都需要O(n)的时间统计,所以总时间复杂度为O(nlogn).
空间复杂度:O(1)
算法不能找到所以重复的数字。
public static int findRepeatNumber(int[] nums) {
int res=-1;
int left=1;//从1开始
int right=nums.length-1;
while(left<=right){
int mid=(right-left)/2+left;//中间数值为开始数值+左右数值差的一半
int totalLeft=mid-left+1;
int actualLeft=statisticsNumbers(nums,left,mid);
if(left==right){
if(actualLeft>1){//结束条件为左右指针重合,且统计的数字个数大于1,否则没有找到 重复数
return left;
}else {
break;
}
}
if(actualLeft>totalLeft){
right=mid;
}else {
left=mid+1;
}
}
return res;
}
public static int statisticsNumbers(int[] nums,int start,int end){
int count=0;
for(int i=0;i<nums.length;i++){
if(nums[i]>=start && nums[i]<=end){
count++;
}
}
return count;
}

浙公网安备 33010602011771号