劍指offer之數(shù)組出現(xiàn)次數(shù)超過一半的數(shù)字

1 問題

數(shù)組中有一個數(shù)字出現(xiàn)了次數(shù)超過數(shù)組長度的一半,請找出這個數(shù)字。

比如{1,2,3,2,2,2,5,4,2},我們知道這個數(shù)是2


 
2 分析

我們數(shù)組元素個數(shù)分為單數(shù)和雙數(shù)

1)數(shù)組長度是單數(shù)的情況下

我們有5個元素,里面至少3個2,還有2個元素我們可能重復(fù)也可能不重復(fù)

我們可以定義一個計數(shù)為1,先用變量保存數(shù)組第一個數(shù)據(jù),然后遍歷數(shù)組,如果發(fā)現(xiàn)后面的數(shù)據(jù)和前面的數(shù)據(jù)不一樣,我們計數(shù)自動減1,如果一樣計量數(shù)自動加1,當計數(shù)為0的時候,我們變量保存數(shù)組后面的一個數(shù),比如{2,1,1,2,2},第二個1和第一個2抵消了,我們變量保存了第三個元素,但是第四元素值2和第3元素值也抵消了,最后的值也就是我么需要的值,如果是有2個不重復(fù)的數(shù)據(jù)比如,{1,3,2,2,2},我們第一個元素和第二個元素的值抵消了,當計量等于0就保存數(shù)組下一個元素,然后計量數(shù)歸1,也就是我們保存第三個元素,然后計量加1,到最后,計量大于1,保存的元素就是我們想要的結(jié)果。


2)數(shù)組長度是雙數(shù)的情況下

比如6個元素,至少有4個元素一樣,2個元素和這4個元素不一樣,這2個元素可能重復(fù)也可能不重復(fù),和上面的分析也一樣,用一個計量和一個變量保存第一個數(shù)據(jù),然后后面的元素和前一個元素不一樣,我們計量數(shù)就自動加1,當計量等于0就保存數(shù)組下一個元素,然后計量數(shù)歸1,最后計量數(shù)肯定大于1,然后我們最后保存變量也是我們想要的結(jié)果。


 
3 代碼實現(xiàn)

    #include <stdio.h>
    #include <stdlib.h>
     
    /*
     *檢測這個數(shù)有沒有超過數(shù)組元素一半值。
     */
    int checkMoreThanHalf(int *datas, int length, int number)
    {
        if (datas == NULL || length <= 0)
        {
            return -1;
        }
        int count = 0;
        for (int i = 0; i < length; ++i)
        {
            if (number == datas[i])
                ++count;
        }
        if (count * 2 > length)
            return 1;
        else
            return -1;
        
    }
     

     
    /*
     *獲取超過數(shù)組元素一半值這個數(shù)
     */
    int getMoreThanHalf(int* datas, int length)
    {
        if (NULL == datas || length <= 0)
            return 0;
        int result = datas[0];
        int times = 1;
        for (int i = 1; i < length; ++i)
        {
            if (times == 0)
            {
                result = datas[i];
                times = 1;
                continue;
            }
            if (datas[i] == result)
            {
                ++times;
            }
            else
            {
                --times;
            }
        }
        int check = checkMoreThanHalf(datas, length, result);
        if (check)
            return result;
        else
            return -1;
    }
     
     
    int main(void)
    {
        int a[] = {2, 1, 2, 3, 2};
        int moreNumber = getMoreThanHalf(a, sizeof(a) / sizeof(int));
        printf("moreNumber is %d\n", moreNumber);
        return 0;
    }



 
4 運行結(jié)果

    moreNumber is 2
     
    

 
5 另外思路

分析:我們知道劍指offer之partition算法 可以找出一個數(shù)據(jù),進行把所有數(shù)據(jù)分為左邊小于其中的一個值,右邊的大于一個值,既然題目說了 有一個數(shù)字出現(xiàn)了次數(shù)超過數(shù)組長度的一半,如果數(shù)組是奇數(shù)個數(shù)的話,比如{1,2,3,2,2};我們知道如果排序后最中間的數(shù)字就是2,也就是我們的中位數(shù),如果數(shù)組是偶數(shù)個數(shù)的話,比如{1,2,3,2,2,2};這里不能只有3個2,不然3個其他數(shù)和題目邏輯矛盾,所以至少是4個2,然后我么進行求這個數(shù)組的中位數(shù)還是2,所以現(xiàn)在題目演變成了,如果這個數(shù)據(jù)排序好了,我們求出中位數(shù)就行,也就是通過partition算法求出返回值為(數(shù)組長度 / 2)的值,然后我們再獲取數(shù)組下表是值為 數(shù)組長度 / 2 的數(shù)組值就行。


 
6 代碼實現(xiàn)

    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    void swap(int* a, int* b)
    {
        int temp = *a;
        *a = *b;
        *b = temp;
    }
     
    void printVector(vector<int> v)
    {
        for (int i = 0; i < v.size(); ++i)
        {
            std::cout << v[i] << "\t";
        }
        std::cout << std::endl;
    }
     
    /*
     *partition算法 記得如果這里是C++我們傳遞的是vector類型,我們記得要加引用,
     *不然改變不了數(shù)據(jù),這里和java傳遞ArrayList不一樣,ArrayList作為參數(shù)可以改變集合里面的值,
     *所以C++如果函數(shù)傳遞非基本數(shù)據(jù)類型,一半都是帶引用的
     */
    int partitionOne(vector<int>& vector, int start, int end)
    {
        if (start > end)
        {
            std::cout << "vector is empty or start > end" << std::endl;
            return -1;
        }
        int pivot = vector[start];
        while (start < end)
        {
            //我們先從尾巴開始
            while (start < end && pivot <= vector[end])
            {
                --end;
            }
            //這里用的數(shù)組賦值,而不是直接用swap交換函數(shù),那么下面的2步也是用數(shù)組賦值,而不是用swap交換函數(shù)
            vector[start] = vector[end];
            while (start < end && pivot >= vector[start])
            {
                ++start;
            }
            vector[end] = vector[start];
            
        }
        //std:cout << "start is " << start << "end is " << end << std::endl;
        vector[start] = pivot;
        //printVector(vector);
        return start;
    }
     
    void getMoreThanHalf(vector<int>& vector)
    {
        if (vector.size() <= 0)
        {
            std::cout << "vector.size is <= 0" << std::endl;
            return;
        }
        int start = 0;
        int end = vector.size() - 1;
        int middle = vector.size() / 2;
        int index = partitionOne(vector, start, end);
        printVector(vector);
        while (index != middle)
        {
            if (index > middle)
            {
              end = index - 1;
              index = partitionOne(vector, start, end);
          }
          else
          {
              start = index + 1;
              index = partitionOne(vector, start, end);
          }
        }
    }
     
    int main()
    {
        vector<int> v2;
        v2.push_back(2);
        v2.push_back(1);
        v2.push_back(2);
        v2.push_back(3);
        v2.push_back(2);
        v2.push_back(-1);
        v2.push_back(2);
       
        printVector(v2);
        
        int a[] = {2, 1, 2, 3, 2};
        getMoreThanHalf(v2);
        std::cout << "value is " << v2[v2.size() / 2] << std::endl;
     
        return 0;
    }

 
 
7 運行結(jié)果

    2    1    2    3    2    -1    2   
    -1    1    2    2    2    3    2   
    value is 2
     
     

 


作者:chen.yu
深信服三年半工作經(jīng)驗,目前就職游戲廠商,希望能和大家交流和學(xué)習(xí),
微信公眾號:編程入門到禿頭 或掃描下面二維碼
零基礎(chǔ)入門進階人工智能(鏈接)