劍指offer面試題3——找到數組中重複的數

題目:
在一個長度爲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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章