採用分治法。以中間為界限。 先計算環繞中間這個數字的眾數情況。然后左右分開遞歸計算結果,取最值就可以。
左右遞歸計算的時候要先做推斷。假如左邊或是右邊的個數都比已求的重數小。就不是必需計算了。即使左邊或是右邊所有都是一樣的。那么他的重數也是小於已求的,所以不是必需進行運算,這一周在加深分治算法的學習,這題着實花了我不少時間。
詳細代碼:
// 用分治法求眾數 #include <iostream> #include <cstdio> using namespace std; // 本程序的關鍵。 以中間的數字為界限。 確定左右起始和終止界限 void split(int s[], int n, int &l, int &r) { int mid = n/2; for(l=0; l<n; ++l) { if (s[l] == s[mid]) break; } for(r=l+1; r<n; ++r) { if (s[r] != s[mid]) break; } } // num 眾數。 maxCnt 重數 void getMaxCnt(int &mid, int &maxCnt, int s[], int n) { int l, r; split(s, n, l, r); // 進行分割。這個函數是本程序的關鍵 int num = n/2; int cnt = r-l; // update if (cnt > maxCnt) { maxCnt = cnt; mid = s[num]; } // l 表示左邊的個數。左邊的個數必須大於 maxCnt 才有必要搜尋 if (l+1 > maxCnt) { getMaxCnt(mid, maxCnt, s, l+1); } // 右邊搜尋, 右邊數組的起始地址要變更 if (n-r > maxCnt) { getMaxCnt(mid, maxCnt, s+r, n-r); } } int main(void) { int s[] = {1, 2, 2, 2, 3, 3, 5, 6, 6, 6, 6}; int n = sizeof(s)/sizeof(s[0]); int maxCnt = 0; int num = 0; getMaxCnt(num, maxCnt, s, n); printf("%d %d\n", num, maxCnt); return 0; }
大概思路圖: