0Pricing
Coding Interview Prep · Ders

Alt Kümeler ve Kuvvet Kümesi

Geri izleme ve bit maskeleme kullanarak bir kümenin tüm alt kümelerini oluşturun; tekrarları sıralayarak ve yinelenen öğeleri atlayarak yönetin.

Alt Kümeler ve Kuvvet Kümesi, CoddyKit'te ücretsiz bir Coding Interview Prep dersidir. Bu, 4 dersinin 2. 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.

Alt Kümeler ve the Kuvvet Kümesi

Kuvvet kümesi, the boş küme ve S kümesinin kendisi de dâhil olmak üzere, S'nin olası tüm subsets koleksiyonudur. n öğeli bir kümede tam olarak 2ⁿ subsets bulunur. [1, 2, 3] için 8 subsets şunlardır: [], [1], [2], [3], [1,2], [1,3], [2,3], [1,2,3]. Bu, tüm olası kombinasyonları, bölmeleri veya seçimleri bulmaya yönelik mülakat sorularında karşılaşılan temel bir birleşimsel problemdir.

# A set of n elements → 2^n subsets
for n in range(5):
    print(f'n={n}: {2**n} subsets')
# n=0: 1  (just the empty set)
# n=1: 2  ([], [x])
# n=2: 4  ([], [a], [b], [a,b])
# n=3: 8  (as enumerated above)
# n=4: 16

Geri İzlemeyle Alt Küme Üretimi

Seç-İncele-Seçimi Geri Al şablonunu kullanın. Temel tasarım kararı şudur: her özyinelemeli çağrıda mevcut kısmi yolu daha fazla öğe seçmeden hemen önce sonuçlara ekleyin. Böylece boş, kısmi ve tam olmak üzere her durum geçerli bir alt küme olarak yakalanır. Son seçilen öğenin yalnızca sağındaki öğeleri değerlendirmek için start dizinini ilerletin; bu, yinelemeleri önler ve sırayı korur.

def subsets(nums):
    result = []
    def backtrack(start, path):
        result.append(list(path))   # every state is a valid subset
        for i in range(start, len(nums)):
            path.append(nums[i])    # CHOOSE
            backtrack(i + 1, path)  # EXPLORE (advance start)
            path.pop()              # UNCHOOSE
    backtrack(0, [])
    return result

print(subsets([1, 2, 3]))
# [[], [1], [1,2], [1,2,3], [1,3], [2], [2,3], [3]]

Bit Maskesi Yaklaşımı

Geri izlemeye bir alternatif bit maskelemedir: her alt küme, bit i'nin 1 olması i öğesinin dâhil edildiği anlamına gelen n bitlik bir sayıya karşılık gelir. 0 ile 2ⁿ - 1 arasında yineleyin ve her sayı için alt kümeyi oluşturmak üzere bitleri çıkarın. Bu yaklaşım yinelemelidir, uygulamada çoğu zaman daha hızlıdır ve kodlaması çok kolaydır. Ancak kısıt içeren problemlere (toplam sınırı gibi) aynı ölçüde temiz biçimde genellenemez.

def subsets_bitmask(nums):
    n = len(nums)
    result = []
    for mask in range(1 << n):  # 0 to 2^n - 1
        subset = []
        for i in range(n):
            if mask & (1 << i):  # bit i is set
                subset.append(nums[i])
        result.append(subset)
    return result

print(subsets_bitmask([1, 2, 3]))
# Same 8 subsets, order may differ

Yinelemeli Alt Küme Üretimi

Yinelemeli yaklaşım, kuvvet kümesini öğe öğe oluşturur. [[] ] ile (boş kümeyle) başlayın. Her yeni öğe için mevcut tüm subsets yapılarını çoğaltın ve yeni öğeyi her kopyaya ekleyin. n öğeyi işledikten sonra the sonuç tüm 2ⁿ subsets yapılarını içerir. Bu, bit düzeyindeki işlemlere aşina olmayanlar için daha okunabilir olsa da bit maskeleme ile eşdeğerdir.

def subsets_iterative(nums):
    result = [[]]  # start with empty set
    for num in nums:
        # For each existing subset, create a new subset with num added
        result += [subset + [num] for subset in result]
    return result

print(subsets_iterative([1, 2, 3]))
# After num=1: [[], [1]]
# After num=2: [[], [1], [2], [1,2]]
# After num=3: [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]

Alt Kümeler II: Yinelenenleri Ele Alma

Girdi yinelenenler içerdiğinde, saf yaklaşım yinelenen alt kümeler üretir. [1, 2, 2] için 2'nin her iki görünümü de [1, 2] sonucunu bağımsız olarak üretir. Çözüm: önce sort kullanarak diziyi sıralayın, ardından mevcut düzeydeki bir aday önceki adayla aynıysa bu adayı atlayın. Özellikle döngüde: if i > start and nums[i] == nums[i-1]: continue.

def subsets_with_dups(nums):
    nums.sort()  # sort to group duplicates together
    result = []
    def backtrack(start, path):
        result.append(list(path))
        for i in range(start, len(nums)):
            # Skip duplicates at the same tree level
            if i > start and nums[i] == nums[i-1]:
                continue
            path.append(nums[i])
            backtrack(i + 1, path)
            path.pop()
    backtrack(0, [])
    return result

print(subsets_with_dups([1, 2, 2]))
# [[], [1], [1,2], [1,2,2], [2], [2,2]]  — no duplicate subsets

Yinelenenleri Atlamanın İşe Yaraması

i > start and nums[i] == nums[i-1] koşulu yinelenen bir değeri yalnızca aynı özyineleme düzeyinde (aynı start) atlar. Aynı değerin farklı derinliklerde seçilmesini engellemez. [1, 2, 2] için: 0. düzeyde ilk 2'yi (indeks 1) dahil ederiz; ardından bir sonraki düzeyde (start=2), [2, 2] oluşturmak için ikinci 2'yi dahil ederiz. Ancak ikinci 2'yi 0. düzeyde yeniden dahil etmeye çalışsaydık koşul bunu yakalayıp atlardı.

# Visual: [1, 2, 2] sorted
# Level 0 (start=0): pick nothing, pick 1, pick first-2, pick second-2 (SKIP)
# Level 1 after picking 1 (start=1): pick first-2, pick second-2 (SKIP)
# Level 2 after picking 1,first-2 (start=2): pick second-2
# → [1,2,2] is generated but only once

nums = [1, 2, 2]
nums.sort()
result_set = set(tuple(sorted(s)) for s in subsets_with_dups(nums[:]))
result_naive = set(tuple(sorted(s)) for s in subsets(nums))
print('With dedup:', sorted(result_set))
print('Same results:', result_set == result_naive)

def subsets(nums):
    result = []
    def bt(start, path):
        result.append(list(path))
        for i in range(start, len(nums)):
            path.append(nums[i]); bt(i+1, path); path.pop()
    bt(0, [])
    return result

def subsets_with_dups(nums):
    result = []
    def bt(start, path):
        result.append(list(path))
        for i in range(start, len(nums)):
            if i > start and nums[i] == nums[i-1]: continue
            path.append(nums[i]); bt(i+1, path); path.pop()
    bt(0, [])
    return result

print(len(subsets_with_dups([1,2,2])), 'unique subsets')  # 6

Sabit Boyutlu Alt Kümeler (k-Kombinasyonları)

Yalnızca tam olarak k boyutundaki alt kümeleri üretmek, bir erken sonlandırma koşulu ekler: kalan öğeler yolu k boyutuna tamamlayamıyorsa aramayı budayınız. Budanabilecek koşul i > n - (k - len(path)) ifadesidir: yeterli sayıda öğe kalmadıysa erken durunuz. Bu yaklaşım, tüm alt kümeleri üretip filtrelemeye kıyasla arama uzayını önemli ölçüde küçültür.

def combine(n, k):
    result = []
    def backtrack(start, path):
        if len(path) == k:
            result.append(list(path))
            return
        # Prune: need (k - len(path)) more elements from [start..n]
        # At most (n - start + 1) elements remain
        if n - start + 1 < k - len(path):
            return  # not enough elements left
        for i in range(start, n + 1):
            path.append(i)
            backtrack(i + 1, path)
            path.pop()
    backtrack(1, [])
    return result

print(combine(4, 2))  # [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
print(len(combine(10, 3)))  # C(10,3) = 120

Kuvvet Kümesi Uygulamaları

Kuvvet kümesi yaklaşımı birçok mülakat varyantında karşınıza çıkar: (1) İki eşit alt kümeye ayırma — herhangi bir alt kümenin toplamının total/2 olup olmadığını kontrol ediniz. (2) İki alt kümenin en büyük XOR'u — tüm alt küme çiftlerini deneyiniz. (3) k öğe seçmenin minimum maliyeti — k-alt kümelerini listeleyiniz. Doğrudan listeleme üstel olsa da bu sorunların birçoğu, yapıyı fark ettiğinizde DP çözümlerine olanak tanır. Kuvvet kümesi yaklaşımı, daha sonra optimizasyon yapacak olsanız bile durum uzayını belirlemenize yardımcı olur.

def max_subset_sum(nums, k):
    '''Maximum sum of any k elements (for comparison: O(n log n) alternative)'''
    # Backtracking approach: enumerate all k-subsets
    max_s = [float('-inf')]
    def bt(start, path, curr_sum):
        if len(path) == k:
            max_s[0] = max(max_s[0], curr_sum)
            return
        remaining_spots = k - len(path)
        for i in range(start, len(nums)):
            if len(nums) - i < remaining_spots: break  # prune
            bt(i+1, path+[nums[i]], curr_sum+nums[i])
    bt(0, [], 0)
    return max_s[0]

# Much faster: just sort and take top k
def max_subset_sum_fast(nums, k):
    return sum(sorted(nums, reverse=True)[:k])

nums = [3, 1, 4, 1, 5, 9, 2, 6]
print(max_subset_sum(nums, 3))       # 20 (9+6+5)
print(max_subset_sum_fast(nums, 3))  # 20

Alt Küme Toplamı Denetimi

Alt Küme Toplamı şunu sorar: dizideki herhangi bir alt kümenin toplamı hedefe eşit mi? Bu sorun geri izleme (üstel) veya DP (polinomsal) kullanılarak çözülebilir. Geri izleme sürümü anlaşılırdır, ancak büyük girdiler için kullanışsız hâle gelir. DP sürümü (mantıksal dp[target+1] tablosu) mülakatlarda tercih edilen yaklaşımdır. Her iki yaklaşımı da anlamak, ödünleşimi açıklamanıza yardımcı olur: geri izleme tüm çözümleri verirken DP, karar problemini verimli biçimde yanıtlar.

# Backtracking version: finds a subset if it exists
def subset_sum_bt(nums, target):
    def bt(start, remaining):
        if remaining == 0: return True
        if remaining < 0 or start == len(nums): return False
        # Include nums[start]
        if bt(start + 1, remaining - nums[start]): return True
        # Exclude nums[start]
        return bt(start + 1, remaining)
    return bt(0, target)

# DP version: O(n * target) time
def subset_sum_dp(nums, target):
    dp = {0}
    for num in nums:
        dp |= {s + num for s in dp}
    return target in dp

print(subset_sum_bt([3, 1, 4, 1, 5], 6))  # True (1+5 or 1+1+4)
print(subset_sum_dp([3, 1, 4, 1, 5], 6))  # True

Alt Küme Listelemenin Karmaşıklığı

Tüm alt kümeleri üretmenin kaçınılmaz O(n × 2ⁿ) zaman karmaşıklığı vardır — her birinin ortalama boyutu n/2 olan 2ⁿ alt küme üretilir. Tüm alt kümeler istendiğinde hiçbir algoritma bundan daha iyisini yapamaz. Bir özelliğe sahip tek bir alt küme isteyen sorunlarda (örneğin en büyük toplam), DP veya açgözlü yaklaşım tercih edilmelidir. Mülakatta temel çıkarım şudur: her zaman tüm alt kümeleri listelemeniz mi gerektiğini, yoksa yalnızca herhangi bir alt kümenin bir koşulu sağlayıp sağlamadığını mı bulmanız gerektiğini sorun — bu yanıt, üstel veya polinomsal zamanın kabul edilebilir olup olmadığını belirler.

import time

def count_subsets(n):
    nums = list(range(n))
    result = []
    def bt(start, path):
        result.append(None)  # count without storing
        for i in range(start, len(nums)):
            path.append(i); bt(i+1, path); path.pop()
    bt(0, [])
    return len(result)

for n in [10, 15, 20]:
    start = time.time()
    cnt = count_subsets(n)
    elapsed = time.time() - start
    print(f'n={n}: {cnt} subsets ({2**n} expected) in {elapsed:.3f}s')

Her Üç Yaklaşımın Karşılaştırılması

Tüm alt kümeleri üretmek için: Geri izleme en genellenebilir yaklaşımdır; yinelenen değerlere ve kısıtlara kolayca uyarlanır. Bit maskeleme kısa ve hızlıdır, ancak n ≤ 30 ile sınırlıdır (tamsayı boyutu nedeniyle). Yinelemeli yaklaşım sezgiseldir ve özyineleme ek yükünü ortadan kaldırır. Bu üç yaklaşım da O(n × 2ⁿ) büyüklüğünde çıktı üretir. Bir mülakatta geri izleme, özyinelemeli karar sürecini anladığınızı gösterir ve daha zor sorunlara genellenebilir. Yaklaşımları tartışırken üçünü de belirtiniz.

# All three approaches for [1,2,3]
nums = [1, 2, 3]

# 1. Backtracking
def bt(start, path, res):
    res.append(list(path))
    for i in range(start, len(nums)):
        path.append(nums[i]); bt(i+1, path, res); path.pop()
res1 = []; bt(0, [], res1)

# 2. Bit masking
res2 = [[nums[i] for i in range(len(nums)) if mask & (1<<i)]
        for mask in range(1<<len(nums))]

# 3. Iterative
res3 = [[]]
for num in nums:
    res3 += [s+[num] for s in res3]

print('All produce', len(nums)**2, '-ish subsets:',
      len(res1), len(res2), len(res3))  # all 8

Hızlı Kontrol

Bu dersteki Veri Yapıları & Algoritmalar — Kodlama Mülakatı Hazırlığı kavramlarını anlayışınızı sınayınız.

Ders Özeti

Bu derste şunları öğrendiniz: geri izleme, daha ileri keşfe geçmeden önce her kısmi yolu sonuçlara ekleyerek tüm alt kümeleri üretir, yinelenen değerler, diziyi sıralayıp aynı özyineleme derinliğinde i > start and nums[i] == nums[i-1] koşuluyla tekrarları atlayarak ele alınır ve bit maskeleme, her alt kümenin benzersiz bir bit maskesine karşılık geldiği kısa bir yinelemeli alternatif sunar. Sırada, farklı kısıtlara sahip ilişkili listeleme sorunları olan Permütasyonlar ve Kombinasyonlar var.

Sıkça Sorulan Sorular

“Alt Kümeler ve Kuvvet Kümesi” dersi ücretsiz mi?

Evet — “Alt Kümeler ve Kuvvet Kümesi” 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.

“Alt Kümeler ve Kuvvet Kümesi” dersinde ne öğreneceğim?

Geri izleme ve bit maskeleme kullanarak bir kümenin tüm alt kümelerini oluşturun; tekrarları sıralayarak ve yinelenen öğeleri atlayarak yönetin. 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 2. dersidir.

“Alt Kümeler ve Kuvvet Kümesi” 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

  1. Geri İzleme Şablonu: Seç, Keşfet, Seçimi Geri Al
  2. Alt Kümeler ve Kuvvet Kümesi
  3. Permütasyonlar ve Kombinasyonlar
  4. N-Vezir ve Kısıt Yayılımı
← Coding Interview Prep Sayfasına Dön