Elemen Mayoritas: Pemungutan Suara Boyer-Moore
Temukan elemen yang muncul lebih dari n/2 kali menggunakan algoritma pemungutan suara Boyer-Moore dengan waktu linear dan ruang O(1), lalu buktikan kebenarannya
Elemen Mayoritas: Pemungutan Suara Boyer-Moore adalah pelajaran Coding Interview Prep gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Coding Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Coding Interview Prep mencakup 4 pelajaran total.
Masalah Elemen Mayoritas
Elemen Mayoritas (LeetCode 169): temukan elemen yang muncul lebih dari n/2 kali dalam larik berukuran n. Elemen mayoritas selalu ada berdasarkan jaminan soal. Untuk [3, 2, 3], jawabannya adalah 3. Untuk [2, 2, 1, 1, 1, 2, 2], jawabannya adalah 2 (muncul 4 kali dari 7 elemen). Pendekatannya berkisar dari pengurutan dalam O(n log n) hingga algoritma pemungutan suara Boyer-Moore yang elegan dengan waktu O(n) dan ruang O(1).
# The majority element appears MORE than n/2 times
# So it appears more than all other elements COMBINED
examples = [
[3, 2, 3], # 3 appears 2/3 times > 1/2
[2, 2, 1, 1, 1, 2, 2], # 2 appears 4/7 times > 3.5
[1], # trivially 1
[1, 1, 2, 1], # 1 appears 3/4 times
]
for e in examples:
from collections import Counter
c = Counter(e)
print(f'Array: {e} → majority: {max(c, key=c.get)} (count {max(c.values())})')Pendekatan Sebelum Boyer-Moore
Tiga pendekatan sebelum pendekatan optimal: (1) Pengurutan: urutkan larik; elemen tengah selalu merupakan mayoritas (karena muncul >n/2 kali). O(n log n), ruang O(1). (2) Peta hash: hitung frekuensi dan kembalikan elemen dengan jumlah > n/2. Waktu O(n), ruang O(n). (3) Pengambilan sampel acak: pilih elemen secara acak dan verifikasi bahwa elemen tersebut muncul >n/2 kali; jumlah percobaan yang diharapkan adalah O(1) (elemen mayoritas dipilih dengan probabilitas >1/2). Boyer-Moore mencapai waktu O(n) dan ruang O(1) secara deterministik.
from collections import Counter
def majority_sort(nums):
nums.sort()
return nums[len(nums) // 2] # middle is always majority
def majority_hashmap(nums):
count = Counter(nums)
return max(count, key=count.get)
def majority_random(nums):
import random
n = len(nums)
while True:
candidate = random.choice(nums)
if nums.count(candidate) > n // 2:
return candidate
nums = [2, 2, 1, 1, 1, 2, 2]
print(majority_sort(nums[:])) # 2
print(majority_hashmap(nums)) # 2Algoritma Pemungutan Suara Boyer-Moore
Algoritma pemungutan suara Boyer-Moore mempertahankan sebuah candidate dan sebuah count. Telusuri larik: jika count == 0, tetapkan elemen saat ini sebagai kandidat baru. Jika elemen saat ini sama dengan kandidat, tambahkan count. Jika tidak, kurangi count. Pada akhir proses, kandidat tersebut adalah elemen mayoritas. Hal ini berhasil karena elemen mayoritas muncul lebih banyak daripada seluruh elemen lainnya jika digabungkan—elemen tersebut tidak mungkin sepenuhnya tersingkir melalui pemungutan suara.
def majority_element(nums):
candidate = None
count = 0
for num in nums:
if count == 0:
candidate = num # new candidate
if num == candidate:
count += 1
else:
count -= 1
return candidate
print(majority_element([3, 2, 3])) # 3
print(majority_element([2, 2, 1, 1, 1, 2, 2])) # 2
print(majority_element([1])) # 1Intuisi di Balik Algoritma
Intuisinya: bayangkan setiap elemen “membatalkan” satu kemunculan elemen yang berbeda. Elemen mayoritas (jumlah > n/2) memiliki lebih banyak kemunculan daripada seluruh elemen lainnya jika digabungkan, sehingga dapat membatalkan semua elemen non-mayoritas dan masih menyisakan beberapa kemunculan. Variabel count melacak keunggulan bersih kandidat saat ini. Ketika count mencapai 0, kandidat saat ini telah dibatalkan oleh jumlah elemen lawan yang sama banyaknya—siapa pun yang muncul berikutnya menjadi kandidat baru.
def bm_trace(nums):
candidate = count = 0
for i, num in enumerate(nums):
if count == 0:
candidate = num
old_count = count
if num == candidate: count += 1
else: count -= 1
print(f'num={num}: candidate={candidate}, count: {old_count}→{count}')
return candidate
bm_trace([2, 2, 1, 1, 1, 2, 2])
# 2→c=1, 2→c=2, 1→c=1, 1→c=0, 1→new cand=1 c=1, 2→c=0, 2→new cand=2 c=1Pembuktian Kebenaran
Pembuktian: misalkan m adalah elemen mayoritas dengan jumlah k > n/2. Pada akhir algoritma, mungkinkah elemen non-mayoritas menjadi kandidat? Agar demikian, m harus telah dibatalkan sepenuhnya. Setiap pembatalan m memerlukan satu kemunculan elemen lain. Untuk membatalkan semua k kemunculan m, diperlukan setidaknya k kemunculan elemen non-m. Namun, k > n/2 dan total elemen non-m adalah n-k < n/2 < k. Kontradiksi—m tidak mungkin dibatalkan sepenuhnya.
# Proof by contradiction visualised:
# Array: [M, M, M, A, B, A, B] (M is majority, 4/7 times)
# Cancellations: M-A, M-B, M-A, M-B would need 4 non-M elements
# But there are only 4 non-M elements and 4 M's > n/2 = 3.5
# So M can survive: after cancellations, at least 1 M remains uncancelled
def verify_bm(tests):
for nums in tests:
result = majority_element(nums)
brute = max(set(nums), key=nums.count)
assert result == brute, f'Mismatch: {nums} → BM={result}, Brute={brute}'
print('All tests passed!')
def majority_element(nums):
c = cnt = 0
for n in nums:
if cnt == 0: c = n
cnt += 1 if n == c else -1
return c
verify_bm([[1],[3,2,3],[1,1,2,1],[2,2,1,1,1,2,2]])Elemen Mayoritas II: Lebih dari n/3
Elemen Mayoritas II (LeetCode 229): temukan semua elemen yang muncul lebih dari n/3 kali. Paling banyak 2 elemen yang dapat memenuhi syarat ini (karena 3 × n/3 = n). Perluas Boyer-Moore dengan mempertahankan dua kandidat beserta dua jumlah. Jika elemen baru tidak cocok dengan kandidat mana pun dan kedua jumlah bernilai positif, kurangi keduanya. Lintasan verifikasi akhir memastikan kandidat mana yang benar-benar melebihi n/3.
def majority_element_ii(nums):
cand1 = cand2 = None
count1 = count2 = 0
for num in nums:
if num == cand1: count1 += 1
elif num == cand2: count2 += 1
elif count1 == 0: cand1, count1 = num, 1
elif count2 == 0: cand2, count2 = num, 1
else:
count1 -= 1
count2 -= 1
# Verify: candidates must exceed n/3
n = len(nums)
return [c for c in [cand1, cand2]
if c is not None and nums.count(c) > n // 3]
print(majority_element_ii([3, 2, 3])) # [3]
print(majority_element_ii([1, 2])) # [1, 2]
print(majority_element_ii([1, 1, 1, 3, 3, 2, 2, 2])) # [1, 2]Generalisasi Boyer-Moore: Mayoritas n/k
Boyer-Moore dapat digeneralisasi untuk menemukan semua elemen yang muncul lebih dari n/k kali dengan menggunakan k-1 kandidat. Paling banyak k-1 elemen yang dapat memenuhi syarat ini. Pertahankan k-1 pasangan (kandidat, jumlah). Jika tidak ada yang cocok dan semua jumlah bernilai positif, kurangi semua jumlah sebesar 1. Algoritma yang digeneralisasi ini berjalan dalam waktu O(n) dan ruang O(k). Dalam wawancara, biasanya cukup jika Anda mengetahui perluasan dua kandidat untuk n/3.
def majority_nk(nums, k):
'''Find all elements appearing more than n/k times.'''
counts = {} # candidate -> count
for num in nums:
counts[num] = counts.get(num, 0) + 1
if len(counts) >= k:
# Remove all candidates by decrementing
new_counts = {c: cnt-1 for c, cnt in counts.items() if cnt > 1}
counts = new_counts
# Verify
threshold = len(nums) // k
return [c for c in counts if nums.count(c) > threshold]
print(majority_nk([1,2,3,1,2,1,2,1], 3)) # [1, 2] (both > 8/3 ≈ 2.67)
print(majority_nk([1,1,1,2,2,3,3,3], 4)) # [1, 3] (both > 8/4 = 2)Elemen Mayoritas dengan Bagi dan Taklukkan
Pendekatan bagi dan taklukkan: bagi larik menjadi dua bagian. Elemen mayoritas dari seluruh larik harus menjadi mayoritas di setidaknya salah satu bagian (jika bukan mayoritas di kedua bagian, elemen tersebut tidak mungkin muncul lebih dari n/2 kali secara keseluruhan). Temukan mayoritas setiap bagian secara rekursif. Jika kedua bagian menghasilkan elemen yang sama, itulah jawabannya. Jika tidak, hitung kedua kandidat di seluruh larik dan kembalikan kandidat yang memiliki lebih banyak kemunculan. Relasi rekurens: T(n) = 2T(n/2) + O(n) → O(n log n).
def majority_dc(nums, lo=None, hi=None):
if lo is None: lo, hi = 0, len(nums) - 1
if lo == hi: return nums[lo]
mid = (lo + hi) // 2
left_maj = majority_dc(nums, lo, mid)
right_maj = majority_dc(nums, mid + 1, hi)
if left_maj == right_maj:
return left_maj
# Count both candidates across the sub-range
left_count = sum(1 for i in range(lo, hi+1) if nums[i] == left_maj)
right_count = sum(1 for i in range(lo, hi+1) if nums[i] == right_maj)
return left_maj if left_count > right_count else right_maj
print(majority_dc([3, 2, 3])) # 3
print(majority_dc([2, 2, 1, 1, 1, 2, 2])) # 2Boyer-Moore Dibandingkan Metode Lain
Perbandingan metode untuk Elemen Mayoritas: Pengurutan: waktu O(n log n), ruang O(1), mengubah data asli. Peta hash: waktu O(n), ruang O(n), tidak mengubah data asli. Bagi dan taklukkan: waktu O(n log n), ruang O(log n) untuk tumpukan pemanggilan. Boyer-Moore: waktu O(n), ruang O(1), satu lintasan, tidak mengubah data asli. Boyer-Moore secara mutlak lebih unggul untuk soal ini. Dalam wawancara, selalu mulai dengan Boyer-Moore setelah menyebutkan secara singkat pendekatan peta hash yang lebih mudah.
import time, random
nums = [random.randint(1, 100) for _ in range(500000)]
# Make element 42 the majority
nums = [42] * 300000 + nums[:200000]
random.shuffle(nums)
start = time.time()
from collections import Counter
hm = Counter(nums).most_common(1)[0][0]
print(f'HashMap: {hm} in {time.time()-start:.4f}s')
def bm(nums):
c = cnt = 0
for n in nums:
if cnt == 0: c = n
cnt += 1 if n == c else -1
return c
start = time.time()
result = bm(nums)
print(f'Boyer-Moore: {result} in {time.time()-start:.4f}s')
print(f'Both correct: {hm == result}')Saat Mayoritas Tidak Dijamin
Boyer-Moore selalu mengembalikan kandidat, tetapi kandidat tersebut mungkin bukan elemen mayoritas jika tidak ada mayoritas. Jika soal tidak menjamin adanya elemen mayoritas, Anda harus melakukan verifikasi: setelah Boyer-Moore, hitung kemunculan kandidat. Jika jumlah kemunculannya > n/2, kandidat tersebut adalah mayoritas. Jika tidak, kembalikan -1 atau None. Verifikasi ini menambahkan satu lintasan O(n) lagi, tetapi keseluruhan algoritma tetap memiliki waktu O(n) dan ruang O(1).
def majority_element_safe(nums):
'''Returns majority element or None if it doesn't exist.'''
# Phase 1: find candidate
candidate = count = 0
for num in nums:
if count == 0:
candidate = num
count += 1 if num == candidate else -1
# Phase 2: verify
if nums.count(candidate) > len(nums) // 2:
return candidate
return None
print(majority_element_safe([3, 2, 3])) # 3 (majority exists)
print(majority_element_safe([1, 2, 3])) # None (no majority)
print(majority_element_safe([1, 2, 1, 2])) # None (tie, neither > n/2)Panduan Wawancara
Pendekatan wawancara untuk Elemen Mayoritas: (1) Sebutkan pengurutan (O(n log n), O(1)) dan peta hash (O(n), O(n)) sebagai pendekatan awal. (2) Perkenalkan Boyer-Moore sebagai solusi optimal O(n) dengan ruang O(1). (3) Jelaskan intuisi saling membatalkan: mayoritas tidak dapat dibatalkan karena memiliki lebih banyak kemunculan daripada seluruh elemen lainnya jika digabungkan. (4) Tulis kodenya dengan rapi dalam 5 baris. (5) Tangani kasus tepi: jika mayoritas tidak dijamin, tambahkan lintasan verifikasi. Struktur ini menunjukkan pemikiran sistematis saat berada di bawah tekanan waktu.
# Clean 5-line Boyer-Moore for interviews
def majority_element(nums):
c, cnt = nums[0], 1
for n in nums[1:]:
cnt += (1 if n == c else -1)
if cnt == 0: c, cnt = n, 1
return c
# Verification (if majority not guaranteed)
def majority_with_check(nums):
c = majority_element(nums)
return c if nums.count(c) > len(nums) // 2 else -1
print(majority_element([3, 2, 3])) # 3
print(majority_element([2, 2, 1, 1, 1, 2, 2])) # 2
print('Time: O(n), Space: O(1)')Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini Anda mempelajari: pemungutan suara Boyer-Moore menemukan elemen mayoritas dalam waktu O(n) dan ruang O(1) menggunakan kandidat dan count yang saling membatalkan elemen non-mayoritas, algoritma ini dapat diperluas untuk mayoritas n/3 dengan dua kandidat dan memerlukan lintasan verifikasi jika mayoritas tidak dijamin, dan pembuktiannya bergantung pada fakta bahwa elemen mayoritas memiliki lebih banyak kemunculan daripada seluruh elemen lainnya jika digabungkan, sehingga pembatalan sepenuhnya tidak mungkin terjadi. Selanjutnya, kita membahas Median Dua Larik Terurut menggunakan pencarian biner pada batas partisi.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Elemen Mayoritas: Pemungutan Suara Boyer-Moore” gratis?
Ya — teks lengkap “Elemen Mayoritas: Pemungutan Suara Boyer-Moore” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Coding Interview Prep, upgrade ke CoddyKit PRO. Kursus Coding Interview Prep mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Elemen Mayoritas: Pemungutan Suara Boyer-Moore”?
Temukan elemen yang muncul lebih dari n/2 kali menggunakan algoritma pemungutan suara Boyer-Moore dengan waktu linear dan ruang O(1), lalu buktikan kebenarannya Kamu berlatih Coding Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Coding Interview Prep?
Tidak diperlukan pengalaman sebelumnya. Coding Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Elemen Mayoritas: Pemungutan Suara Boyer-Moore” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Coding Interview Prep ini?
Ya. Setiap pelajaran Coding Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Templat Divide and Conquer
- Menghitung Inversi Menggunakan Merge Sort Termodifikasi
- Elemen Mayoritas: Pemungutan Suara Boyer-Moore
- Median dari Dua Array Terurut