題目:
在一個長度爲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();
}