Unsur Majoriti: Pengundian Boyer-Moore
Cari unsur yang muncul lebih daripada n/2 kali menggunakan algoritma pengundian Boyer-Moore bermasa linear dan ruang O(1), serta buktikan ketepatannya.
Unsur Majoriti: Pengundian Boyer-Moore ialah pelajaran DSA Interview Prep percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran DSA Interview Prep, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus DSA Interview Prep merangkumi sejumlah 4 pelajaran.
Masalah Unsur Majoriti
Unsur Majoriti (LeetCode 169): cari unsur yang muncul lebih daripada n/2 kali dalam tatasusunan sepanjang n. Unsur majoriti sentiasa wujud berdasarkan jaminan masalah. Bagi [3, 2, 3], jawapannya ialah 3. Bagi [2, 2, 1, 1, 1, 2, 2], jawapannya ialah 2 (muncul 4 kali daripada 7). Pendekatan yang tersedia merangkumi pengisihan dalam O(n log n) hingga algoritma pengundian Boyer-Moore O(n) O(1) yang elegan.
# 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 optimum: (1) Pengisihan: isihkan tatasusunan; unsur tengah sentiasa merupakan unsur majoriti (kerana ia muncul >n/2 kali). O(n log n), ruang O(1). (2) Peta cincang: kira kekerapan dan pulangkan unsur dengan kiraan > n/2. Masa O(n), ruang O(n). (3) Persampelan rawak: pilih unsur rawak dan sahkan bahawa ia muncul >n/2 kali; secara jangkaan memerlukan O(1) percubaan (unsur majoriti dipilih dengan kebarangkalian >1/2). Boyer-Moore mencapai masa O(n) dan ruang O(1) secara pasti.
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 Pengundian Boyer-Moore
Algoritma pengundian Boyer-Moore mengekalkan candidate dan count. Telusuri tatasusunan: jika count == 0, tetapkan unsur semasa sebagai calon baharu. Jika unsur semasa sepadan dengan calon, naikkan count. Jika tidak, kurangkan count. Pada akhir algoritma, calon tersebut ialah unsur majoriti. Kaedah ini berfungsi kerana unsur majoriti muncul lebih banyak daripada gabungan semua unsur lain — unsur itu tidak mungkin disingkirkan sepenuhnya melalui pengundian.
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 Sebalik Algoritma
Intuisi: bayangkan setiap unsur “membatalkan” satu kemunculan unsur yang berbeza. Unsur majoriti (kiraan > n/2) mempunyai lebih banyak kemunculan daripada gabungan semua unsur lain, jadi ia boleh membatalkan semua unsur bukan majoriti dan masih mempunyai kemunculan yang berbaki. Pemboleh ubah count menjejaki kelebihan bersih calon semasa. Apabila count mencapai 0, calon semasa telah dibatalkan oleh bilangan unsur yang menentang yang sama banyak — sesiapa yang muncul selepas itu menjadi calon baharu.
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=1Bukti Ketepatan
Bukti: biarkan m ialah unsur majoriti dengan kiraan k > n/2. Pada akhir algoritma, mungkinkah unsur bukan majoriti menjadi calon? Untuk itu berlaku, m mestilah telah dibatalkan sepenuhnya. Setiap pembatalan m memerlukan satu kemunculan unsur lain. Untuk membatalkan kesemua k kemunculan m, anda memerlukan sekurang-kurangnya k kemunculan unsur bukan m. Tetapi k > n/2 dan jumlah unsur bukan m ialah n-k < n/2 < k. Percanggahan — 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]])Unsur Majoriti II: Lebih daripada n/3
Unsur Majoriti II (LeetCode 229): cari semua unsur yang muncul lebih daripada n/3 kali. Paling banyak 2 unsur boleh memenuhi syarat ini (kerana 3 × n/3 = n). Luaskan Boyer-Moore untuk mengekalkan dua calon dengan dua kiraan. Apabila unsur baharu tidak sepadan dengan mana-mana calon dan kedua-dua kiraan adalah positif, kurangkan kedua-duanya. Laluan pengesahan akhir mengesahkan calon 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]Boyer-Moore Umum: Majoriti n/k
Boyer-Moore boleh digeneralisasikan untuk mencari semua unsur yang muncul lebih daripada n/k kali dengan menggunakan k-1 calon. Paling banyak k-1 unsur boleh memenuhi syarat ini. Kekalkan k-1 pasangan (calon, kiraan). Apabila tiada pasangan yang sepadan dan semua kiraan adalah positif, kurangkan semua kiraan sebanyak 1. Algoritma umum ini berjalan dalam masa O(n) dan ruang O(k). Dalam temu duga, pengetahuan tentang peluasan dua calon (n/3) biasanya sudah mencukupi.
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)Unsur Majoriti dengan Kaedah Bahagi dan Takluk
Pendekatan bahagi dan takluk: bahagikan tatasusunan kepada dua bahagian. Unsur majoriti bagi keseluruhan tatasusunan mestilah menjadi majoriti dalam sekurang-kurangnya satu bahagian (jika ia bukan majoriti dalam kedua-dua bahagian, ia tidak mungkin muncul lebih daripada n/2 kali secara keseluruhan). Cari majoriti bagi setiap bahagian secara rekursif. Jika kedua-dua bahagian bersetuju, itulah jawapannya. Jika tidak, kira kedua-dua calon merentasi keseluruhan tatasusunan dan pulangkan calon yang mempunyai lebih banyak kemunculan. Hubungan 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 berbanding Kaedah Lain
Perbandingan kaedah untuk Unsur Majoriti: Isihan: masa O(n log n), ruang O(1), mengubah data asal. Peta cincang: masa O(n), ruang O(n), tidak mengubah data asal. Bahagi dan takluk: masa O(n log n), ruang tindanan panggilan O(log n). Boyer-Moore: masa O(n), ruang O(1), satu laluan, tidak mengubah data asal. Boyer-Moore jelas mengatasi kaedah lain untuk masalah ini. Dalam temu duga, sentiasa mulakan dengan Boyer-Moore selepas menyebut secara ringkas pendekatan peta cincang 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}')Apabila Unsur Majoriti Tidak Dijamin
Boyer-Moore sentiasa mengembalikan calon, tetapi calon itu mungkin bukan unsur majoriti jika tiada unsur majoriti wujud. Jika masalah tidak menjamin kewujudan unsur majoriti, anda mesti membuat pengesahan: selepas Boyer-Moore, kira kemunculan calon. Jika kiraan > n/2, calon itu ialah unsur majoriti. Jika tidak, pulangkan -1 atau Tiada. Pengesahan ini menambah satu lagi laluan O(n), tetapi keseluruhan algoritma kekal pada masa 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 Temu Duga
Pendekatan temu duga untuk Unsur Majoriti: (1) Nyatakan pengisihan (O(n log n), O(1)) dan peta cincang (O(n), O(n)) sebagai pendekatan awal. (2) Perkenalkan Boyer-Moore sebagai penyelesaian optimum O(n) O(1). (3) Terangkan intuisi pembatalan: unsur majoriti tidak boleh dibatalkan kerana ia mempunyai lebih banyak kemunculan daripada gabungan semua unsur lain. (4) Tulis kod dengan kemas dalam 5 baris. (5) Kendalikan kes pinggir: jika unsur majoriti tidak dijamin, tambahkan laluan pengesahan. Struktur ini menunjukkan pemikiran sistematik di bawah tekanan masa.
# 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)')Semakan Pantas
Uji pemahaman anda tentang konsep Struktur Data & Algoritma — Persediaan Temu Duga Pengekodan daripada pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini, anda telah mempelajari bahawa: pengundian Boyer-Moore mencari unsur majoriti dalam masa O(n) dan ruang O(1) menggunakan calon serta kiraan yang membatalkan unsur bukan majoriti, algoritma ini boleh dilanjutkan kepada majoriti n/3 dengan dua calon dan memerlukan laluan pengesahan apabila unsur majoriti tidak dijamin, dan bukti bergantung pada fakta bahawa unsur majoriti mempunyai lebih banyak kemunculan daripada gabungan semua unsur lain, menjadikan pembatalan sepenuhnya mustahil. Seterusnya, kita akan menangani Median Dua Tatasusunan Terisih menggunakan carian binari pada sempadan pembahagian.
Pelajari Python dengan tutor kecerdasan buatan — percuma
Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.
- Kursus
- 30
- Pelajaran
- 120
Soalan Lazim
Adakah pelajaran “Unsur Majoriti: Pengundian Boyer-Moore” percuma?
Ya — sebanyak 3 pelajaran dalam laluan pembelajaran DSA Interview Prep, termasuk “Unsur Majoriti: Pengundian Boyer-Moore”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus DSA Interview Prep merangkumi sejumlah 4 pelajaran.
Apakah yang akan saya pelajari dalam “Unsur Majoriti: Pengundian Boyer-Moore”?
Cari unsur yang muncul lebih daripada n/2 kali menggunakan algoritma pengundian Boyer-Moore bermasa linear dan ruang O(1), serta buktikan ketepatannya. Anda berlatih DSA Interview Prep menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.
Adakah saya memerlukan pengalaman untuk memulakan DSA Interview Prep?
Tiada pengalaman terdahulu diperlukan. Pembelajaran DSA Interview Prep di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.
Berapa lamakah pelajaran “Unsur Majoriti: Pengundian Boyer-Moore” diambil?
Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.
Bolehkah saya menulis dan menjalankan kod dalam pelajaran DSA Interview Prep ini?
Ya. Setiap pelajaran DSA Interview Prep menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.
Semua pelajaran dalam kursus ini
- Templat Bahagi dan Takluk
- Mengira Penyongsangan Menggunakan Isihan Gabung Terubah Suai
- Unsur Majoriti: Pengundian Boyer-Moore
- Median Dua Tatasusunan Terisih