43、输出数组中重复的数字
题目:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1。数据范围:0≤n≤10000 。
进阶:时间复杂度O(n) ,空间复杂度O(n)
示例:
输入:[2,3,1,0,2,5,3]
输出:2
说明:2或者3 都是对的
思路
思路一: 穷举法
最简单的办法就是遍历数组的每个元素,然后将当前访问的数组与剩余的数组元素作大小比较,如果遇到相等的,则说明这个元素的值重复了,直接返回结果;如果不等,则继续遍历下一个数组元素。
思路二: 优化版 思路一: 是一种比较笨的方法,是利用穷举法思想来解决问题的。显然,这种解法不是很好,因为它的时间复杂度是 O(n^2),算法的执行效率太低,如果有时间限制的话,肯定是通不过测试的。
根据题意可知,
- 一元数组 nums 有 n 个数组元素,元素取值范围在 0~n-1 之间,而数组的下标范围也是 0 ~ n-1。
- 我们可以将数组元素与其对应的下标值作大小比较,如果相等则跳过,遍历下一个数组元素;
- 如果不等,则将该元素与以该元素值为下标所对应的数组元素进行比较, 如果相等,就表示找到了一个重复的元素,并返回该元素的值,不相等则将这两个元素值交换。
具体实现
思路一:
#include<stdio.h>
int findRepeatNumber(int* nums, int numsSize) {
if (nums == NULL || numsSize <= 0){
printf("数组为空!");
return -1;
}
for (int i = 0; i < numsSize; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] == nums[j]) {
printf("%d", nums[i]);
return nums[i];
}
}
}
return -1;
}
int main()
{
int numbers[7] = { 2 ,3 ,1 ,0, 2, 5 ,3 };
int length = 7;
findRepeatNumber(numbers, length);
return 0;
}
复杂度
空间复杂度O(1)---没有开辟新的存储空间。 时间复杂度O(n^2)---最坏情况,遍历完整个数组,两个for循环。
思路二:
#include<stdio.h>
int findRepeatNumber(int* nums, int numsSize) {
if (nums == NULL || numsSize <= 0)
return -1;
int i = 0;
while (i < numsSize) {
if (i == nums[i]) {
i++;
continue;
}
else {
int tmp = nums[i]; //将a[i]赋值给临时变量tmp
if (nums[i] == nums[tmp]) //如果相等,则返回重复元素值
{
printf("%d", nums[i]);
return nums[i];
}
else { //如果不等,则交换
nums[i] = nums[tmp];
nums[tmp] = tmp;
}
}
}
return -1;
}
int main()
{
int numbers[7] = { 2 ,3 ,1 ,0, 2, 5 ,3 };
int length = 7;
findRepeatNumber(numbers, length);
return 0;
}
复杂度
时间复杂度O(n) --- 有 n 个数组元素,循环n次 空间复杂度O(n)--- n代表有 n 个数组元素