题目:找出数组中重复的数字
在一个长度为n的数组里的所有数字都在1~n-1的范围内。数字中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。
请找出数组中任意一个重复的数字。例如,如果输入长度为78的数组{1, 2, 3, 5, 3, 1, 4, 0 },那么对应的输出是重复的数字是1和3。
- 方法1:
先将输入的数组排序,其次从头到尾扫描排序后的数组。这里排序一个长度为n的数组需要O(nlogn)的时间。 - 方法2:
利用哈希表。时间复杂度为O(1),但是空间复杂度为O(n) - 方法3:
- 从头到尾依次扫描这个数组中的每个数字。当扫描到下标为i的数字时,首先比较这个数字(用 arr[i] 表示)是不是等于i。如果是,则接着扫描下一个数字;如果不是,则在拿它和第 arr[i] 个数字进行比较。
- 如果 arr[i] 和 arr[arr[i]] 相等,就找到一个重复的数字;如果不相等,就把第i个数字和第 arr[i] 个数字交换,把 arr[arr[i]] 放到属于它的位置。
- 接下来重复比较、交换的过程,直到我们发现一个重复的数字。
时间复杂度为O(n),空间复杂度为O(1)
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
enum Status{
False,
True,
};
size_t status = False;
int duplicate(int arr[], size_t sz)
{
int i = 0;
if (arr == NULL)
//空指针,非法输入
return status;
for (i = 0; i < sz; i++)
{
if (arr[i]<0 || arr[i]>sz - 1)
//数组中的值越界,非法值
return status;
}
for (i = 0; i < sz; i++)//依次扫描
{
while (arr[i] != i)//步骤1
{
if (arr[i] == arr[arr[i]])//步骤2
{
status = True;
printf("%d ",arr[i]);
break;
}
int tmp = arr[i];
arr[i] = arr[tmp];
arr[tmp] = tmp;
}
}
return status;
}
int main()
{
int a[] = { 1, 2, 3, 5, 3, 1, 4, 0 };
size_t sz = sizeof(a) / sizeof(a[0]);
int status = duplicate(a, sz);
if (status == False)
printf("没有重复数字\n");
else
printf("有重复数字\n");
system("pause");
return 0;
}
注意细节:
- 长度为n的数组里包含一个或者多个重复的数字。
- 数组中不包含重复的数字
- 无效输入测试用例(输入空指针;长度为n的数组中包含0~n-1之外数字)。