题目: 在一个长度为n的数组里的所有数字都在 0 ~ (n-1)的范围内。数组中 某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组{2,3,1,0,2,5,3},那么对应输出重复 的数字为 2 或者 3 。
思路一:看到这道题,我的思路是先将这个数组进行排序。排序完毕后,遍历数组,如果出现两个相邻的数字相等,那么这个数字就是重复的。代码如下
#include <stdio.h>
int Find(int* arr, int sz)
{
int i = 0;
for(i = 0; i < sz; ++i) {
int j = 0;
for(j = i; j < sz - 1; ++j) {
if(arr[j] == arr[j+1]) {
return arr[j];
}
}
}
return -1;
}
void swap(int* a, int* b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
int main()
{
int arr[] = {2,3,1,0,2,5,3};
int sz = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for(; i < sz; ++i) {
int j = 0;
for(j = i; j < sz - 1; ++j) {
if(arr[j] > arr[j+1]) {
swap(&arr[j], &arr[j+1]);
}
}
}
int ret = Find(arr, sz);
printf("ret expected 2 or 3, ret actual %d\n",ret);
return 0;
}
思路二:由于这个数组内的元素是由0~(N-1)组成,所以可以利用角标与元素一一对应的关系,来寻找那个相同的元素。
#include <stdio.h>
int FindSameArr(int arr[], int size)
{
if(arr == NULL) {
return -1;
}
int i = 0;
for(; i < size; ++i) {
int tmp = arr[i];
while(arr[i] != i) {
if(arr[i] == arr[tmp]) {
return arr[i];
}
arr[i] = arr[tmp];
arr[tmp] = tmp;
}
}
return -1;
}
int main()
{
int arr[] = {2,3,1,0,2,5,3};
int size = sizeof(arr)/sizeof(arr[0]);
int ret = FindSameArr(arr, size);
printf("expect ret 3 or 2,actual ret %d\n",ret);
return 0;
}
这样的话,这个代码的时间复杂度就为O(N)。并且相比思路一其效率也较高。
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!