剑指offer50_数组中重复的数字_题解
数组中重复的数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中第一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
返回描述:
如果数组中有重复的数字,函数返回true,否则返回false。
如果数组中有重复的数字,把重复的数字放到参数duplication[0]中。(ps:duplication已经初始化,可以直接赋值使用。)
分析
方案一:哈希算法(hash)
算法流程:
- 初始化: 新建 \(map\) ,记为 \(dic\) ;
- 遍历数组 \(nums\) 中的每个数字 \(num\) :
- 当 \(num\) 在 \(dic\) 中,说明重复,返回 \(num\) ;
- 将 \(num\) 添加至 \(dic\) 中;
- 返回 \(false\) 。
代码
/**
1.时间复杂度:O(n)
2.空间复杂度:O(n)
**/
class Solution
{
public:
bool duplicate(int numbers[], int length, int* duplication)
{
map<int, bool> dic;
for (int i = 0; i < length; i++)
{
int num = numbers[i];
dic[num] = dic.find(num) == dic.end();
if (!dic[num])
{
*duplication = num;
return true;
}
}
return false;
}
};
方案二:原地算法(in-place)
算法思想:
利用现有数组设置标志,当一个数字被访问过后,设置该数字对应索引的数值 \(-n\)
当再次遇到相同数字时,会发现该数字对应索引上的数值已经小于0,直接返回这个数即可。
算法流程:
- 遍历数组 \(numbers\) 的每个数字 \(num\)
- 设置索引 \(index\) 为 \(num\)
- 当 \(index<0\) 时,将 \(index\) 加 \(n\) 作为索引,保证 \(index\) 始终为初始值
- 当 \(numbers[index]>=0\) 时,将 \(numbers[index]\) 减 \(n\),由于每个数字 \(num\) 保证在 \([0,n-1]\),所以一定有 \(numbers[index]<0\) ,代表 \(index\) 已经被访问过
- 当 \(numbers[index]<0\) 时,说明 \(index\) 指向的该数字之前已经被访问过,返回 \(index\) 即可
- 返回 \(false\) ,没有找到该数字
代码
/**
1.时间复杂度:O(n)
2.空间复杂度:O(1)
**/
class Solution
{
public:
bool duplicate(int numbers[], int length, int *duplication)
{
for (int i = 0; i < length; i++)
{
int index = numbers[i];
if (index < 0)
{
index += length;
}
if (numbers[index] >= 0)
{
numbers[index] -= length;
}
else
{
duplication[0] = index;
return true;
}
}
return false;
}
};