給定長度為 n 的陣列,已知存在一個元素出現次數 > n/2,求該元素。要求時間 O(n)、空間 O(1)。
用二維陣列記錄 [值, 次數],遍歷原陣列更新計數,最後掃描找最大值。時間 O(n²),空間 O(n)——效率極低,僅供練習。
排序後,出現 > n/2 次的元素必佔據中間位置 a[n/2]。時間取決於排序演算法(通常 O(n log n)),空間 O(1) 或 O(log n)。優點:代碼簡單;缺點:破壞原陣列順序,非最優。
將陣列視為「陣營對決」:候選元素 candidate 與計數器 count。遍歷陣列:
count == 0,當前元素成為新候選,count = 1。count++;否則 count--。因目標元素佔多數,其「得分」抵消所有其他元素後仍為正,最終候選即為答案。
int majorityElement(int *nums, int n) {
int candidate = 0, count = 0;
for (int i = 0; i < n; ++i) {
if (count == 0) candidate = nums[i];
count += (nums[i] == candidate) ? 1 : -1;
}
return candidate; // 題目保證存在多數元素,無需二次驗證
}
每次 count-- 相當於將一個「非候選元素」與一個「候選元素」配對抵消。因候選元素數量 > n/2,抵消完所有非候選元素後,至少剩下一個候選元素,故最終 count >= 1。
需第二遍掃描驗證候選元素實際出現次數是否 > n/2。
| 方法 | 時間 | 空間 | 備註 |
|---|---|---|---|
| 暴力計數 | O(n²) | O(n) | 教學示範 |
| 排序取中位 | O(n log n) | O(1) | 破壞順序 |
| Boyer-Moore | O(n) | O(1) | 最優解,單遍歷 |
std::nth_element 取中位數 O(n) 平均時間,但投票法常數更小且無副作用。