题目:
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路:
方法一:两个for循环,用vector存储重复的数,可输出所有数字和重复次数。时间复杂度O(n^2)
方法二:先排序,然后顺序查找。(先排序再查找,参考排序代码)
方法三:使用哈希表,记录关键字及记录出现的次数
方法四:注意:数组元素范围在0~n-1之间。因此,若没有重复的数字,则所有的元素排序后,数字i将出现在下标为i的位置。若有重复,可能有一些位置没有元素,一些位置有多个。利用这种方法,依次扫描每个数字,①判断是否和对应下标相等?相等,i++;不相等,判断num[i]是否和以num[num[i]]相等?若不相等,则交换;若相等,则找到第一个重复的元素。
/************************************************************************/
/* 剑指offer3:数组中重复的数字 */
/************************************************************************/
#include<stdio.h>
#include <math.h>
#include <io.h>
#include <iostream>
#include <vector>
using namespace std;
/************************************************************************/
/* 第一种方法:两个for循环遍历,然后用vector向量记录重复数字和次数:时间复杂度O(N^2) */
/************************************************************************/
void iterateNum1()
{
int a[]={2,3,1,0,2,5,3,0};
int len=sizeof(a)/sizeof(a[0]);
vector<int> Result;
// hash_map<int,int>m;
for (int i=0;i<len;i++)
{
int count=0;
int n;
for (int j=0;j<len;j++)
{
if (a[i]==a[j])
{
count++;
n=i;
}
}
if (count>1)
{
Result.push_back(a[n]);
}
}
for (int i=0;i<Result.size()/2;i++)
{
cout<<Result[i]<<endl;
}
}
/************************************************************************/
/* 第二种方法:用哈希表 时间复杂度O(n) ;空间需要一个大小为O(n)的哈希表 */
/************************************************************************/
#include <hash_map>
#include <map>
void iterateNum2_hash()
{
int a[8]={2,3,1,0,2,5,3,0};
int len=sizeof(a)/sizeof(a[0]);
hash_map<int,int>m;
int count=0;
for (int i=0;i<len;i++)
{
++m[a[i]];
}
auto map_it = m.cbegin(); //遍历关联容器
while(map_it != m.cend())
{
if (map_it->second >1)
{
cout<<map_it->first<<map_it->second<<endl;
++map_it;
}
else
++map_it;
}
}
/************************************************************************/
/* 方法三:数字范围在0~n-1之间,则下标i是否对应数字m?对应,扫描下一个;不对应,和第m个位置数字相比?相等,重复;不等,交换到对应位置 */
/************************************************************************/
bool duplicate(int numbers[], int length, int *duplication)
{
//首先判断边界条件
if (numbers==nullptr || length<=0)
return false;
for (int i=0;i<length;i++)
{
if (numbers[i]<0 || numbers[i]>length-1)
return false;
}
for(int i=0;i<length;i++)
{
while(numbers[i]!=i)
{
//while循环一直进行,i和num[i]不相等就一直交换,直到找到第一个重复的数。
if (numbers[i]==numbers[numbers[i]])
{
*duplication =numbers[i];
return true;
}
//不相等的话,交换两个数据
int temp=numbers[i];
numbers[i]=numbers[temp];
numbers[temp]=temp;
}
}
return false;
}
//===========测试代码============
bool contains(int array[], int length, int number)
{
for (int i=0;i<length;i++)
{
if (array[i]==number)
{
cout<<array[i]<<endl;
return true;
}
}
return false;
}
void test(char* testName, int numbers[], int lengthNnumbers, int expected[],int expectedExpected, bool validArgument)
{
printf("%s begins:\n",testName);
int duplication;
bool validInput = duplicate(numbers, lengthNnumbers,&duplication);
if (validArgument == validInput)
{
if (validArgument)
{
if (contains(expected,expectedExpected,duplication))
{
printf("passed.\n");
}
else
printf("failed.\n");
}
else
printf("passed.\n");
}
else
printf("failed.\n");
}
//重复数字是数组中最小的数字
void test1()
{
int numbers[]={2,1,3,1,4};
int duplications[]={1};
test("test1",numbers,sizeof(numbers)/sizeof(int),duplications,sizeof(duplications)/sizeof(int),true);
}
//重复数字是数组中最大的数
void test2()
{
int numbers[]={2,4,3,1,4};
int duplications[]={4};
test("test2",numbers,sizeof(numbers)/sizeof(int),duplications,sizeof(duplications)/sizeof(int),true);
}
//多个重复的数字
void test3()
{
int numbers[]={2,4,3,2,4};
int duplications[]={2,4};
test("test3",numbers,sizeof(numbers)/sizeof(int),duplications,sizeof(duplications)/sizeof(int),true);
}
//没有重复数字
void test4()
{
int numbers[]={1,2,3,4,5};
int duplications[]={-1};
test("test4",numbers,sizeof(numbers)/sizeof(int),duplications,sizeof(duplications)/sizeof(int),false);
}
//无效的输入
void test6()
{
int *numbers=NULL;
int duplications[]={-1};
test("test6",numbers,0,duplications,sizeof(duplications)/sizeof(int),false);
}
int main()
{
test1();
test2();
test3();
}