剑指offer:数组中重复的数字
题目:一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些
数字时重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
请找出数组中任意一个重复的数字。例如,如果输入长度为7的数组{2,3,1,0,2,5,3},
那么对应输出的重复的数字是2或3。
思路:
1.先将数组进行排序,然后从排序的数组中找出重复的数字。排序:O(nlogn)
2.hash table:从头到尾扫描数组的每个数字,每扫到一个数字,都可以用O(1)
的时间判断hash table中是否有该数字。若hash table中没有,就将其加入,如果
hash table中已经存在该数字,就找到了一个重复的数字。
该算法的时间复杂度是:O(n),但以一个大小为O(n)的hash table为代价
3.从头到尾扫描数组中的每个数字。当扫描到下标为i的数字时,首先比较这个数字
(用m表示)是否等于i。如果时,则接着扫描下一个数字;如果不是,则拿它和第m个数字
进行比较。如果它和第m个数字相等,就找到了一个重复的数字(该数字在下标为i和m的位置都出现)
如果它和第m个数字不相等,就把第i个数字和第m个数字进行交换,把m放到属于它的位置。接下
重复直到发现一个重复的数字。
实现:
注:所有的代码牛客网通过,可以直接提交。希望在本地调试的见:如何进行本地调试
使用插入排序
相应的可以换成时间复杂度更低的快速排序(O(nlogn))
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
void Insert_sort(int array[], int length){
for (int i = 0; i < length; i++)
{
for (int j = i; j >= 0; j--)
{
if (less(array[j], array[j - 1]))
{
exch(&array[j], &array[j - 1]);
}
}
}
}
void exch(int* a, int* b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
bool less(int a, int b){
if (a <= b) return true;
else return false;
}
bool duplicate(int numbers[], int length, int* duplication) {
if (numbers == NULL)
{
return false;
}
Insert_sort(numbers, length);
int candidate = numbers[0];
for (int i = 1; i < length; i++)
{
if (numbers[i] == candidate)
{
*duplication = numbers[i];
return true;
}
else
{
candidate = numbers[i];
}
}
return false;
}
};
指针复习
指针理解
指针没有初始化时,它所指向的内存是不存在的。所以不可以建立指针变量p1而不进行初始化,就直接传入函数duplicate; 或者可以建立 int 型变量 p2,然后直接传入 &p2。
sizeof 函数:sizeof(对象)返回的是对象自身的类型的大小。
要注意数组作为函数的参数进行传递时,会自动退化为对应类型的指针。
使用hash table
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
if (numbers == NULL) return false;
int temp[length];
for (int i = 0; i < length; i++){
temp[i] = -1;
}
for (int j = 0; j < length; j++)
{
if (temp[numbers[j]] == -1) temp[numbers[j]] = 1;
else
{
*duplication = numbers[j];
return true;
}
}
return false;
}
};
使用方法三
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
//采用方法三:
void exch(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
bool duplicate(int numbers[], int length, int* duplication) {
if (numbers == NULL) return false;
for (int i = 0; i < length; i++)
{
int m =numbers[i];
if (i == m) continue;
else
{
if (numbers[m] == m)
{
*duplication = m;
return true;
}
else
{
exch(&m, &numbers[m]);
}
}
}
return false;
}
};
注意:加上额外的判断,因为题目中要求0~n-1,所以不再这个范围的都要返回false。