Çoğunluk Öğesi: Boyer-Moore Oylaması
Doğrusal zamanlı ve O(1) alan kullanan Boyer-Moore oylama algoritmasıyla n/2’den fazla görünen öğeyi bulun ve doğruluğunu kanıtlayın.
Çoğunluk Öğesi: Boyer-Moore Oylaması, CoddyKit'te ücretsiz bir Coding Interview Prep dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Coding Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Coding Interview Prep kursu toplamda 4 dersten oluşur.
Çoğunluk Öğesi Problemi
Çoğunluk Öğesi (LeetCode 169): uzunluğu n olan bir dizide n/2 kereden fazla görünen öğeyi bulunuz. Problemin garantisi gereği çoğunluk öğesi her zaman vardır. [3, 2, 3] için cevap 3'tür. [2, 2, 1, 1, 1, 2, 2] için cevap 2'dir (7 öğenin 4'ünde görülür). Yaklaşımlar O(n log n) ile sıralamadan zarif O(n) zamanlı, O(1) alanlı Boyer-Moore oylama algoritmasına kadar uzanır.
# 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())})')Boyer-Moore Öncesi Yaklaşımlar
En iyi yaklaşımdan önce değerlendirilebilecek üç yaklaşım: (1) Sıralama: diziyi sıralayınız; orta öğe her zaman çoğunluktur (çünkü >n/2 kez görülür). O(n log n), O(1) alan. (2) Karma tablo: sıklıkları sayınız ve count > n/2 olan öğeyi döndürünüz. O(n) zaman, O(n) alan. (3) Rastgele örnekleme: rastgele bir öğe seçip >n/2 kez göründüğünü doğrulayınız; beklenen deneme sayısı O(1)'dir (çoğunluk öğesinin seçilme olasılığı >1/2'dir). Boyer-Moore, deterministik olarak O(n) zaman ve O(1) alan sağlar.
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)) # 2Boyer-Moore Oylama Algoritması
Boyer-Moore oylama algoritması, bir candidate ve bir count tutar. Dizi boyunca ilerleyiniz: count == 0 ise mevcut öğeyi yeni aday olarak ayarlayınız. Mevcut öğe adayla eşleşiyorsa count değerini artırınız. Aksi halde count değerini azaltınız. Sonunda aday, çoğunluk öğesidir. Bunun nedeni çoğunluk öğesinin diğer tüm öğelerin toplamından fazla görünmesidir; bu nedenle oylarla tamamen elenemez.
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])) # 1Algoritmanın Ardındaki Sezgi
Sezgi: her öğenin farklı bir öğenin bir oluşumunu 'iptal ettiğini' düşününüz. Çoğunluk öğesi (count > n/2), diğer tüm öğelerin toplamından daha fazla oluşuma sahiptir; bu nedenle çoğunluk olmayan tüm öğeleri iptal edebilir ve yine de geriye oluşumları kalır. count değişkeni mevcut adayın net üstünlüğünü izler. count 0'a ulaştığında mevcut aday, aynı sayıda karşıt öğe tarafından iptal edilmiştir — sırada ortaya çıkan öğe yeni adaydır.
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=1Doğruluk Kanıtı
Kanıt: m, count k > n/2 olan çoğunluk öğesi olsun. Algoritmanın sonunda çoğunluk olmayan bir öğe aday olabilir mi? Bunun için m'nin tamamen iptal edilmiş olması gerekir. m'nin her iptali, başka bir öğenin bir oluşumuna mal olur. m'nin k oluşumunun tamamını iptal etmek için çoğunluk olmayan öğelerden en az k oluşum gerekir. Ancak k > n/2 ve m dışındaki öğelerin toplamı n-k < n/2 < k'dir. Çelişki — m tamamen iptal edilemez.
# 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]])Çoğunluk Öğesi II: n/3'ten Fazla
Çoğunluk Öğesi II (LeetCode 229): n/3 kereden fazla görünen tüm öğeleri bulunuz. En fazla 2 öğe bunu sağlayabilir (çünkü 3 × n/3 = n). Boyer-Moore'u iki sayımla birlikte iki aday tutacak şekilde genişletiniz. Yeni bir öğe iki adayla da eşleşmediğinde ve her iki sayım da pozitif olduğunda ikisini de azaltınız. Son bir doğrulama geçişi, hangi adayların gerçekten n/3 değerini aştığını doğrular.
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]Genelleştirilmiş Boyer-Moore: n/k Çoğunluğu
Boyer-Moore, n/k kereden fazla görünen tüm öğeleri k-1 aday kullanarak bulacak şekilde genelleştirilebilir. Bu koşulu en fazla k-1 öğe sağlayabilir. k-1 (aday, count) çifti tutunuz. Hiçbiri eşleşmediğinde ve tüm sayılar pozitif olduğunda, tüm sayıları 1 azaltınız. Bu genelleştirilmiş algoritma O(n) zaman ve O(k) alan kullanır. Mülakatlarda iki adaylı (n/3) uzantısını bilmek genellikle yeterlidir.
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)Böl ve Yönet ile Çoğunluk Öğesi
Bir böl ve yönet yaklaşımı: diziyi ikiye bölünüz. Tam dizinin çoğunluk öğesi, en az bir yarıda çoğunluk olmak zorundadır (ikisinde de çoğunluk değilse genel olarak n/2'den fazla görünemez). Her yarının çoğunluğunu özyinelemeli olarak bulunuz. İki yarı aynı fikirdeyse cevap budur. Aksi halde her iki adayı tam dizi boyunca sayınız ve daha fazla görüneni döndürünüz. Bağıntı: 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 ve Diğer Yöntemler
Çoğunluk Öğesi için yöntem karşılaştırması: Sıralama: O(n log n) zaman, O(1) alan, diziyi değiştirir. Karma tablo: O(n) zaman, O(n) alan, diziyi değiştirmez. Böl ve yönet: O(n log n) zaman, O(log n) çağrı yığını alanı. Boyer-Moore: O(n) zaman, O(1) alan, tek geçiş, diziyi değiştirmez. Boyer-Moore bu problem için kesin olarak üstündür. Mülakatlarda, daha kolay karma tablo yaklaşımından kısaca söz ettikten sonra her zaman Boyer-Moore ile başlayınız.
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}')Çoğunluğun Garanti Edilmediği Durumlar
Boyer-Moore her zaman bir aday döndürür, ancak hiç çoğunluk öğesi yoksa bu aday çoğunluk öğesi olmayabilir. Problem çoğunluk öğesini garanti etmiyorsa doğrulama yapmanız gerekir: Boyer-Moore'dan sonra adayın oluşumlarını sayınız. count > n/2 ise çoğunluk öğesidir. Aksi halde -1 veya None döndürünüz. Bu doğrulama bir O(n) geçiş daha ekler ancak genel algoritmayı O(n) zamanlı, O(1) alanlı tutar.
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)Mülakat Çözüm Yaklaşımı
Çoğunluk Öğesi için mülakat yaklaşımı: (1) Başlangıç yaklaşımları olarak sıralamadan (O(n log n), O(1)) ve karma tablodan (O(n), O(n)) söz ediniz. (2) En iyi O(n) O(1) çözüm olarak Boyer-Moore'u tanıtınız. (3) İptal etme sezgisini açıklayınız: çoğunluk öğesi, diğer tüm öğelerin toplamından daha fazla göründüğü için iptal edilemez. (4) Beş satırda temiz bir şekilde kodlayınız. (5) Sınır durumunu ele alınız: çoğunluk garanti edilmiyorsa bir doğrulama geçişi ekleyiniz. Bu yapı, zaman baskısı altında sistematik düşünmeyi gösterir.
# 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)')Hızlı Kontrol
Bu dersteki Veri Yapıları ve Algoritmalar — Kodlama Mülakatı Hazırlığı kavramlarını ne kadar anladığınızı sınayınız.
Ders Özeti
Bu derste şunları öğrendiniz: Boyer-Moore oylaması, çoğunluk olmayan öğeleri iptal eden bir aday ve count kullanarak O(n) zaman ve O(1) alan içinde çoğunluk öğesini bulur, algoritma iki adayla n/3 çoğunluğuna genişler ve çoğunluk garanti edilmediğinde bir doğrulama geçişi gerektirir ve kanıt, çoğunluk öğesinin diğer tüm öğelerin toplamından daha fazla oluşuma sahip olduğu gerçeğine dayanır; bu da tamamen iptal edilmeyi imkânsız kılar. Sırada, bölüm sınırında ikili arama kullanarak İki Sıralı Dizinin Medyanını ele alacağız.
Sıkça Sorulan Sorular
“Çoğunluk Öğesi: Boyer-Moore Oylaması” dersi ücretsiz mi?
Evet — “Çoğunluk Öğesi: Boyer-Moore Oylaması” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Coding Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Coding Interview Prep kursu toplamda 4 dersten oluşur.
“Çoğunluk Öğesi: Boyer-Moore Oylaması” dersinde ne öğreneceğim?
Doğrusal zamanlı ve O(1) alan kullanan Boyer-Moore oylama algoritmasıyla n/2’den fazla görünen öğeyi bulun ve doğruluğunu kanıtlayın. Coding Interview Prep ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Coding Interview Prep öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Coding Interview Prep, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.
“Çoğunluk Öğesi: Boyer-Moore Oylaması” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Coding Interview Prep dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Coding Interview Prep dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Böl ve Yönet Şablonu
- Değiştirilmiş Birleştirmeli Sıralamayla Terslikleri Sayma
- Çoğunluk Öğesi: Boyer-Moore Oylaması
- İki Sıralı Dizinin Ortancası