题目:查找数组中重复的数字
给定一个长度为 n 的整数数组 nums,数组中所有的数字都在 0∼n−1 的范围内。
数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
请找出数组中任意一个重复的数字。
注意:如果某些数字不在 0∼n−1 的范围内,或数组中不包含重复数字,则返回 -1;
样例
给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。
返回 2 或 3。
解题方法1 – 哈希表
从头到尾桉顺序扫描整个数组,并且把数组加入到新的hash数组中;用O(1)的时间判断这个数字出现的次数是否大于1,出现次数大于1次就返回。
时间复杂度 O(n)
空间复杂度 O(n) 开辟一个新的数组
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
if (nums.empty()) return -1;
int n = nums.size();
int *hash = new int[n]; //新建一个长度为n的数组hash
fill(hash, hash + n, 0); //给hash数组初始化
for (int i = 0; i < n; i++)
{
if (nums[i] < 0 || nums[i] >= n) return -1;
} //之前把这两部分写在一个循环中,但是这是不对的,因为必须保证所有的数字都是在给定范围内再去查找重复项才有意义
//在一个循环红中,可能先找到有重复的数字就直接返回了,但是后面还有不在范围内的数,所以错误。
for (int i = 0; i < n; i++)
{
hash[nums[i]]++;
if(hash[nums[i]] > 1)
return nums[i];
}
delete hash; //数组不再使用的时候要delete
return -1;
}
};
【Tips】
1.数组的长度设为变量
本地VS2015编译器不允许数组长度为变量,所以用new/delete的方法。
int hash[n]; //在线编译器可以通过,但是vs2010不行 可以采用用new/delete的方法
int *h = new int(n); //新建一个长度为n的数组hash
delete h;
2.用fill()函数填充容器
2.1 fill()函数填充普通一维数组
int array[8] = {0}; // myvector: 0 0 0 0 0 0 0 0
fill (array,array+4,5); // myvector: 5 5 5 5 0 0 0 0
fill (array+3,array+6,8); // myvector: 5 5 5 8 8 8 0 0
array代表的就是array[]的起始地址,而array+4代表的就是在起始向后偏移4个位置的元素
2.2 fill()函数填充vector
vector<int> myvector (8); // myvector: 0 0 0 0 0 0 0 0
fill (myvector.begin(),myvector.begin()+4,5); // myvector: 5 5 5 5 0 0 0 0
fill (myvector.begin()+3,myvector.end()-2,8); // myvector: 5 5 5 8 8 8 0 0
其初始地址就是vector.begin(),末位地址就是vector.end()
2.3. fill()函数填充二维数组
int G[6][4];
fill(G[0],G[0]+6*4,520); //G[0]是二维数组的首地址,6*4表示二维数组的长度
解题方法2 – 按坑一个个排序,i-- nums[i]
数组中的数都在0~n-1的范围内,如果数组中没有重复的数字,那么当数组排序之后下表i对应的应该是数字i;
但是有重复数字,所以会出现多个下标对应同一个数字,
即nums[i] != i && nums[i] == nums[nums[i] ,说明这个数nums[i]出现多次
时间复杂度 O(n)
空间复杂度 O(1)
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
if(nums.empty()) return -1;
int n = nums.size();
for(int i = 0 ; i < n ; i ++)
{
if(nums[i] < 0 || nums[i] > n-1) return -1;
}
for(int i = 0 ; i < n ; i++)
{
while(nums[i] != i) //按照一个个坑进行排序
{
//要先进行判断再排序
if(nums[i] == nums[nums[i]]) return nums[i]; //这个数不仅在它原本的坑上出现,还在其他坑上也出现
swap(nums[i],nums[nums[i]]); //交换,以满足按坑排序
}
}
return -1;
}
};