一、題目:
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為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; }
*!
明顯的能看見代碼量越來越少,希望自己以后碰到問題,如果時間多了,可以多想想。一個好的算法,不僅僅能有效的解決問題,而且還可以減少很多代碼量。