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