剑指offer笔记——面试题3:数组中重复的数字
题目一:找出数组中重复的数字
问题描述:在一个长度为n的数组里的所有数字都在0~n-1的范围内,找出数组中任意一个重复的数字。如长度为7的数组{2, 3, 1, 0, 2, 5, 3},判断是重复的,且输出重复的数字2或3
代码:
时间复杂度为O(n),空间复杂度为O(1)
#include <iostream>
/**
* 查看某一数组是否存在重复数字
* @param a 数组指针
* @param asize 数组长度
* @param duplication 用于存储重复的数字
* @return 若存在重复数组,则返回1,否则返回0
*/
bool duplicate(int a[], int asize, int *duplication)
{
if(a == nullptr) // 注意非法输入
{
std::cout << "the array doesn't exsit" << std::endl;
return false;
}
for(int i = 0; i < asize;)
{
if(a[i] == i)
{
i++;
}
else
{
if(a[i] >= asize || a[i] < 0) // 注意非法输入
{
std::cout << "the array don't satisfy the need" << std::endl;
return false;
}
if(a[a[i]] == a[i])
{
*duplication = a[i];
return true;
}
else
{
// 这里注意赋值的先后顺序不能改,否则a[i]先改变,则a[a[i]]不再是想要的那个元素
int temp;
temp = a[a[i]];
a[a[i]] = a[i];
a[i] = temp;
}
}
}
return false;
}
int main()
{
int a[] = {2, 3, 1, 0, 2, 5, 3};
int *duplication = new int;
std::cout << duplicate(a, sizeof(a)/sizeof(int), duplication) << '\t' << *duplication << std::endl;
return 0;
}
运行结果:
题目二:不修改数组找出重复的数字
问题描述:在一个长度为n+1的数组里的所有数字都在1~n的范围内(所以至少有一个数字是重复的),请找出数组中任意一个重复的数字,但不能修改输入的数组。如输入数组{2, 3, 5, 4, 3, 2, 6, 7}
时间复杂度O(n),空间复杂度O(n)的方法
代码:
#include <iostream>
/**
* 查看某一数组是否存在重复数字
* @param a 数组指针
* @param asize 数组长度
* @param duplication 用于存储重复的数字
* @return 若存在重复数组,则返回1,否则返回0
*/
bool duplicate(const int *a, int asize, int *duplication)
{
if(a == NULL) // 注意非法输入
{
std::cout << "the array doesn't exsit" << std::endl;
return false;
}
for(int i = 0; i < asize; i++)
{
if(a[i] >= asize || a[i] <= 0) // 注意非法输入
{
std::cout << "the array don't satisfy the need" << std::endl;
return false;
}
}
int temp[asize] = {0};
for(int i = 0; i < asize; i++)
{
if(temp[a[i]] != a[i])
{
temp[a[i]] = a[i];
}
else
{
*duplication = a[i];
return true;
}
}
return false;
}
int main()
{
int a[] = {2, 3, 5, 4, 3, 2, 6, 7};
int *duplication = new int;
std::cout << duplicate(a, sizeof(a)/sizeof(int), duplication) << '\t' << *duplication << std::endl;
return 0;
}
运行结果:
时间复杂度O(nlogn),空间复杂度O(1)的方法
代码:
#include <iostream>
/**
* 查看某一数组是否存在重复数字
* @param a 数组指针
* @param asize 数组长度
* @param duplication 用于存储重复的数字
* @return 若存在重复数组,则返回1,否则返回0
*/
bool duplicate2(const int *a, int asize, int *duplication)
{
if(a == NULL)
{
std::cout << "the array doesn't exsit" << std::endl;
return false;
}
int start = 1;
int end = asize - 1;
for(;start <= end;)
{
int middle = (start + end) / 2;
int count = 0; // 数组中在start到middle范围内的数的个数
for(int i = 0; i < asize; i++)
{
if(a[i] >= asize || a[i] < 1)
{
std::cout << "the array don't satisfy the need" << std::endl;
return false;
}
if(a[i] >= start && a[i] <= middle)
count++;
}
if(start == end) // 此时start到end范围内只有一个数,如果该数在数组中有重复则说明数组中有重复元素,否则就一定没有重复元素
{
if(count > 1)
{
*duplication = start;
return true;
}
else
{
return false;
}
}
if(count > (middle - start +1)) // 如果个数大于区间大小,说明在此区间内有重复数字,再次二分查找
end = middle;
else
start = middle + 1;
}
return false;
}
int main()
{
int a[] = {2, 3, 5, 4, 3, 2, 6, 7};
int *duplication = new int;
std::cout << duplicate2(a, sizeof(a)/sizeof(int), duplication) << '\t' << *duplication << std::endl;
return 0;
}
运行结果: