查找在數組出現次數超過一半的數字


一、題目:

      數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。

二、分析:

  1). 暴力統計(遍歷統計):統計超過數組長度一半的數,最簡單也是最常用的思路就是暴力統計,遍歷數組中所有元素,記錄每一個元素出現的次數,最后找出出現次數最大的那個數。

    優點:准確、思路簡單,符合人的常規思維模式。

            缺點:有很多額外的輔助信息,比如需要一個二維數組來記錄,並且二維數組的長度至少為原數組長度的一半(這兒是針對C語言,數組申請需要提前知道數組長度,非高等語言中的可變數組),需要進行額外的多次查找位置,最后還需要進行查找出現次數最大的那個數。

     2). 暴力統計確實簡單,但是問題也很明顯,那么能不能找個更加簡單的算法?答案是可以的。

           排序算法:因為這個數出現的次數超過列表的一半,那么排序后的結果,最中間的那個數一定是需求的數。算法復雜度取決於排序算法的選取。

     優點:復雜度全部依賴於你選的排序算法。

     缺點:先決條件是已知一定有一個數字出現的次數超過了數組長度的一半,而且復雜度完全依賴於排序算法。

     3). 排序算法時間復雜度比暴力統計時間復雜度肯定都高的,再介紹一個比較好的算法。

          抵消策略:因為這個數出現的次數超過了列表的一半,那么我拿這個數和其余所有的數進行抵消,結果一定還會剩下至少一個。

          算法:①. 申請兩個變量 tempValue,tempIndex,初始化tempValue為array[0],tempIndex為1 .

                   ②. 從數組的第二個數開始,依次和tempValue進行比較,如果不一樣,tempIndex -= 1,如果一樣,tempIndex += 1;運算后如果tempIndex為0,把array[i] 賦值給tempValue,tempIndex修改為1.直到數組完結。

                  ③. 最后tempValue一定是需要的數。

         優點:這個算法優點很明顯了,無論是從時間上還是從空間上,都兼顧到了。

         缺點:缺點依然是先決條件:一定有一個數字出現的次數超過了數組的一半。

    4). 3)的變形版,依據原理完全一樣。

         算法:①. 從列表中移除兩個不相等的數字。

      ②. 重復①,直到數組只剩下一個數為止。

      ③. 上面剩下的那個數一定是需要的那個數

     5). 你來補充

**** 修改 *****

上面算法2、3、4 中,都沒有給出題目的解,這兒就再絮叨一點,其實只需要再次遍歷一遍數組,加一下個數,判斷個數是否大於數組長度的一半即可,這就一個for循環,一個判斷即可。

三、代碼:

  代碼不是重點,全看個人編程能力,我這兒只是一個樣例,證明我自己做過。

      遍歷算法:

int traverseEach(int *array,int number) {
    
    int *tempArray = (int *)malloc(sizeof(int)*(number / 2 + 1) * 2);
    
    //全部初始化為0
    for (int i = 0; i < number * 2; i ++) {
        tempArray[i] = 0;
    }
    
    int maxNumber = 0;
    int returnValue = 0;
    int maxCount = 0;
    int tempIndex = 0;
    
    for (int i = 0; i < number; i ++) {
        
        tempIndex = 0;
        if (maxCount == 0) {
            //初始化一下
            tempArray[maxCount] = array[i];
            tempArray[number + i] = 1;
            maxCount = 1;
        } else {
            //
            for (; tempIndex < maxCount; tempIndex ++) {
                if (tempArray[tempIndex] == array[i]) {
                    tempArray[number + tempIndex] += 1;
                    break;
                }
            }
            if (tempIndex == maxCount) {
                //新的
                tempArray[tempIndex] = array[i];
                tempArray[number + tempIndex] += 1;
                maxCount += 1;
            }
        }
        
        if (maxNumber < tempArray[number + tempIndex]) {
            maxNumber = tempArray[number + tempIndex];
            returnValue = tempArray[tempIndex];
        }
    }
    
    free(tempArray);
    //檢驗是否大於一半
    if (maxNumber <= number/2) {
        returnValue = 0;
    }
    return returnValue;
}

  排序算法:(這兒就是用冒泡排序做個例子)

void maopSort(int *array,int number) {
    int changed = 1;
    for (int i = number - 1; i > 0 ; i --) {
        if (changed == 0) {
            break;
        }
        changed = 0;
        for (int j = 0; j < i; j++) {
            if (array[j] > array[j+1]) {
                //exchange
                array[j] += array[j+1];
                array[j+1] = array[j] - array[j+1];
                array[j] = array[j] - array[j+1];
                changed = 1;
            }
        }
    }
}

int sortRelu(int *array, int number){
    maopSort(array, number);
    return array[number/2];
}

  抵消策略:

int neutralize(int *array,int number) {
    
    int returnValue = array[0];
    int count = 1;
    
    for (int i = 1; i < number; i ++) {
        if (returnValue == array[i]) {
            count += 1;
        } else {
            count -= 1;
        }
        if (count <= 0) {
            count = 1;
            returnValue = array[i];
        }
    }
    return returnValue;
}

 

*!

明顯的能看見代碼量越來越少,希望自己以后碰到問題,如果時間多了,可以多想想。一個好的算法,不僅僅能有效的解決問題,而且還可以減少很多代碼量。

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM