DSA Interview Prep · Ders

N-Vezir ve Kısıt Yayılımı

Sütun ve köşegen kümelerini kullanarak kısıtları O(1) sürede kontrol edecek şekilde N×N tahtasına N vezir yerleştirin; çözümleri sayma ile listeleme arasındaki farkı tartışın.

4. ders / 413 adım

N-Vezir ve Kısıt Yayılımı, CoddyKit'te ücretsiz bir DSA Interview Prep dersidir. Bu, 4 dersinin 4. 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, DSA Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. DSA Interview Prep kursu toplamda 4 dersten oluşur.

N Vezir Problemi

N Vezirleri problemi (LeetCode 51/52), hiçbir iki vezirin birbirine saldıramayacağı şekilde N veziri N×N satranç tahtasına yerleştirmenizi ister. Vezirler satırlar, sütunlar ve her iki köşegen boyunca saldırır. N=4 için tam olarak 2 çözüm vardır. Klasik sürüm olan N=8 için 92 çözüm vardır. Bu, arama uzayını kısıt denetimiyle büyük ölçüde budayan temel geri izleme problemidir.

# N-Queens constraints:
# 1. Exactly one queen per row
# 2. No two queens in the same column
# 3. No two queens on the same diagonal (top-left to bottom-right)
# 4. No two queens on the same anti-diagonal (top-right to bottom-left)

# For N=4, the 2 solutions:
sol1 = ['.Q..', '...Q', 'Q...', '..Q.']
sol2 = ['..Q.', 'Q...', '...Q', '.Q..']
print('N=4 solutions:')
for row in sol1: print(row)
print()
for row in sol2: print(row)

Her Satıra Bir Vezir Yerleştirme

Hiçbir iki vezir aynı satırı paylaşamayacağından tam olarak bir vezir her satıra yerleştirilir. Geri izleme, her satır için bir sütun seçerek satır satır özyinelemeli biçimde ilerler. Bu, vezir başına N² seçimlik arama uzayını her satır için yalnızca N sütuna indirerek N^N başlangıç dalı oluşturur; ancak kısıtlar bu sayıyı büyük ölçüde azaltır. Özyineleme derinliği N'dir (her satır için bir düzey) ve dallanma katsayısı en fazla N'dir.

def solve_n_queens(n):
    results = []
    queens = []  # queens[row] = column of queen in that row
    
    def backtrack(row):
        if row == n:
            # Build the board representation
            board = []
            for r in range(n):
                board.append('.' * queens[r] + 'Q' + '.' * (n - queens[r] - 1))
            results.append(board)
            return
        for col in range(n):
            if is_valid(row, col):
                queens.append(col)   # CHOOSE
                backtrack(row + 1)   # EXPLORE
                queens.pop()         # UNCHOOSE
    
    def is_valid(row, col):
        for r, c in enumerate(queens):
            if c == col: return False             # same column
            if abs(row - r) == abs(col - c): return False  # diagonal
        return True
    
    backtrack(0)
    return results

print(len(solve_n_queens(4)), 'solutions for N=4')  # 2
print(len(solve_n_queens(8)), 'solutions for N=8')  # 92

Kümelerle O(1) Kısıt Denetimi

Yerleştirilmiş tüm vezirleri tarayarak geçerliliği denetlemek, aday başına O(N) maliyet getirir ve en kötü durumda toplam algoritma maliyetini O(N² × N!) yapar. Üç küme tutarak her geçerlilik denetimini O(1) zamanına indirebiliriz: cols (dolu sütunlar), diag (sol üstten sağ alta köşegenler için satır-sütun değerleri) ve anti_diag (sağ üstten sol alta köşegenler için satır+sütun değerleri). Aynı köşegendeki vezirler aynı satır-sütun değerini; aynı karşı köşegendeki vezirler ise aynı satır+sütun değerini paylaşır.

def solve_n_queens_fast(n):
    results = []
    cols = set()       # occupied columns
    diag = set()       # row - col (positive diagonal)
    anti = set()       # row + col (negative diagonal)
    queens = []
    
    def backtrack(row):
        if row == n:
            board = ['.' * c + 'Q' + '.' * (n-c-1) for c in queens]
            results.append(board)
            return
        for col in range(n):
            if col in cols or (row-col) in diag or (row+col) in anti:
                continue  # PRUNE: constraint violated
            # CHOOSE
            cols.add(col); diag.add(row-col); anti.add(row+col); queens.append(col)
            backtrack(row + 1)  # EXPLORE
            # UNCHOOSE
            cols.remove(col); diag.remove(row-col); anti.remove(row+col); queens.pop()
    
    backtrack(0)
    return results

print(len(solve_n_queens_fast(8)))  # 92

Köşegen Değişmezinin Açıklanması

Köşegenlere ilişkin temel gözlem şudur: sol üstten sağ alta uzanan aynı köşegendeki tüm hücreler aynı row - col değerine sahiptir. Örneğin (0,0), (1,1) ve (2,2) hücrelerinin tamamında row-col=0 olur. Aynı karşı köşegendeki tüm hücreler ise aynı row + col değerine sahiptir: (0,2), (1,1) ve (2,0) hücrelerinin tamamında row+col=2 olur. Bunlar, köşegen çakışmalarını O(N) doğrusal tarama yerine O(1) küme aramasıyla denetlememizi sağlayan sabit zamanlı değişmezlerdir.

# Visualise the diagonal invariants for a 4x4 board
n = 4
print('row-col values (same diagonal):')
for r in range(n):
    print([r-c for c in range(n)])

print('row+col values (same anti-diagonal):')
for r in range(n):
    print([r+c for c in range(n)])

# Verify: (0,0) and (2,2) share diag value 0
print('(0,0) diag:', 0-0, '| (2,2) diag:', 2-2)  # both 0
# Verify: (0,2) and (2,0) share anti-diag value 2
print('(0,2) anti:', 0+2, '| (2,0) anti:', 2+0)  # both 2

Çözümleri Sayma: N Vezirleri II

N Vezirleri II (LeetCode 52) tahtaları değil, yalnızca çözüm sayısını ister. Bu sayede küçük bir iyileştirme yapılabilir: tahta oluşturma adımını atlayıp yalnızca bir sayacı artırınız. Kümeler yerine bit maskeleri kullanmak, sayma işlemini işlem başına neredeyse O(1) hızına çıkarabilir. Çözüm sayısı tekdüze olmayan biçimde artar: 1(N=1), 0(N=2), 0(N=3), 2(N=4), 10(N=5), 4(N=6), 40(N=7), 92(N=8).

def total_n_queens(n):
    count = [0]
    cols = set(); diag = set(); anti = set()
    def backtrack(row):
        if row == n:
            count[0] += 1
            return
        for col in range(n):
            if col in cols or (row-col) in diag or (row+col) in anti:
                continue
            cols.add(col); diag.add(row-col); anti.add(row+col)
            backtrack(row + 1)
            cols.remove(col); diag.remove(row-col); anti.remove(row+col)
    backtrack(0)
    return count[0]

for n in range(1, 11):
    print(f'N={n}: {total_n_queens(n)} solutions')

Hız için Bit Maskeli N Vezirleri

Çok büyük N değerleri için bit maskesi uygulaması önemli ölçüde daha hızlı çalışır. Üç tamsayıyı bit maskesi olarak kullanınız: cols, left_diag (her satırda sola kayar) ve right_diag (her satırda sağa kayar). Kullanılabilir sütunlar ((1<<n)-1) & ~(cols|left_diag|right_diag) ifadesiyle bulunur. Her kullanılabilir sütunu bit = available & -available (ayarlanmış en düşük bit) ile çıkarıp özyinelemeli çağrı yapınız. Bu yöntem, bit düzeyinde işlemlerle kısıt denetimi başına O(1) zaman elde eder.

def total_n_queens_bitmask(n):
    full = (1 << n) - 1  # all n columns set
    count = [0]
    def bt(cols, left_diag, right_diag):
        if cols == full:
            count[0] += 1
            return
        available = full & ~(cols | left_diag | right_diag)
        while available:
            bit = available & -available  # lowest set bit
            available &= available - 1   # remove lowest bit
            bt(cols | bit,
               (left_diag | bit) << 1,
               (right_diag | bit) >> 1)
    bt(0, 0, 0)
    return count[0]

for n in range(1, 13):
    print(f'N={n}: {total_n_queens_bitmask(n)}')

Kısıt Yayılımı Kavramı

Kısıt yayılımı, basit budamanın ötesine geçer: bir vezir yerleştirdikten sonra, sonraki satırlardaki tüm geçersiz konumları hemen çıkarır ve eler. Bu, her adayda geçerliliği denetlemekten daha agresiftir; dallanmadan önce arama uzayını proaktif biçimde daraltırsınız. En ünlü örnek, SAT çözücülerinde ve Sudoku çözücülerinde görülen Yay Tutarlılığıdır; burada bir rakamın yerleştirilmesi, aynı satır, sütun ve 3×3 kutudaki seçenekleri eler.

# Constraint propagation in Sudoku:
# After placing 5 in cell (0,0):
# - Row 0: no other cell can have 5
# - Column 0: no other cell can have 5
# - Box (0,0)-(2,2): no other cell can have 5
# This is propagated BEFORE branching further

# Simple demo: remaining valid columns after placing queens
def remaining_columns(n, queens):
    cols = set(q for q in queens)
    diags = set(r - q for r, q in enumerate(queens))
    anti_diags = set(r + q for r, q in enumerate(queens))
    row = len(queens)
    return [c for c in range(n)
            if c not in cols
            and (row-c) not in diags
            and (row+c) not in anti_diags]

print(remaining_columns(8, [0]))  # valid cols for row 1 after placing col 0 in row 0

Sudoku Çözücü

Sudoku, kısıt yayılımının klasik problemidir. Her boş hücrede geçerli rakam seçenekleri, aynı satırda, sütunda veya 3×3 kutuda zaten bulunmayan rakamlardır. Geri izlemeli çözücü şu adımları izler: ilk boş hücreyi bulur, her geçerli rakamı dener ve özyinelemeli olarak ilerler. Bir çelişkiye ulaşılırsa (geçerli rakamı olmayan boş hücre), geri izleme yapılır. İyi Sudoku çözücüleri, geri izlemeden önce kısıt yayılımını (kurşun kalem işaretleri) de uygular.

def solve_sudoku(board):
    def is_valid(r, c, num):
        for i in range(9):
            if board[r][i] == num: return False  # row
            if board[i][c] == num: return False  # col
        br, bc = (r//3)*3, (c//3)*3
        for i in range(3):
            for j in range(3):
                if board[br+i][bc+j] == num: return False  # box
        return True
    
    def backtrack():
        for r in range(9):
            for c in range(9):
                if board[r][c] == '.':
                    for d in '123456789':
                        if is_valid(r, c, d):
                            board[r][c] = d
                            if backtrack(): return True
                            board[r][c] = '.'
                    return False  # no valid digit found
        return True  # no empty cells: solved
    
    backtrack()
    return board

# Mini test with a solvable board (simplified)
print('Sudoku solver implemented')

En Çok Kısıtlanan Değişken Buluşsal Yöntemi

Kısıt tatmini problemleri için önemli bir optimizasyon: her zaman en çok kısıtlanan değişkeni (en az geçerli seçeneğe sahip hücreyi) seçin. Sudoku'da bir hücrede yalnızca 1 geçerli rakam varsa, onu hemen doldurmak zorunludur; geri izleme gerekmez. Bu tür hücreleri önce seçmek, arama ağacının derinliğini büyük ölçüde azaltır. Bu, yapay zekâdaki kısıt programlamasında kullanılan Minimum Kalan Değerler (MRV) buluşsal yöntemidir.

def solve_sudoku_mrv(board):
    '''Find cell with fewest valid choices (MRV heuristic).'''
    def valid_choices(r, c):
        nums = set('123456789')
        for i in range(9):
            nums.discard(board[r][i])
            nums.discard(board[i][c])
        br, bc = (r//3)*3, (c//3)*3
        for i in range(3):
            for j in range(3):
                nums.discard(board[br+i][bc+j])
        return nums
    
    def find_mrv():
        best = (10, -1, -1, set())  # (choices_count, r, c, choices)
        for r in range(9):
            for c in range(9):
                if board[r][c] == '.':
                    choices = valid_choices(r, c)
                    if len(choices) < best[0]:
                        best = (len(choices), r, c, choices)
        return best[1], best[2], best[3]
    
    def backtrack():
        r, c, choices = find_mrv()
        if r == -1: return True  # no empty cells
        for d in choices:
            board[r][c] = d
            if backtrack(): return True
            board[r][c] = '.'
        return False
    
    backtrack()
    return board

N-Vezir Çözüm Sayıları Tablosu

N-vezir çözümlerinin sayısı şu iyi bilinen diziyi izler: N=1: 1, N=2: 0, N=3: 0, N=4: 2, N=5: 10, N=6: 4, N=7: 40, N=8: 92, N=9: 352, N=10: 724. Bilinen bir kapalı biçimli formül yoktur; sayının hesaplanması gerekir. N=27 için yaklaşık 2.34 × 10^17 çözüm vardır. Mülakat soruları genellikle N ≤ 9 için sorulur. Üstel büyümeyi anlamak, daha büyük N değerlerinde bit maskesi optimizasyonunun neden önemli olduğunu açıklar.

def count_queens(n):
    '''O(1) per constraint check using sets.'''
    count = [0]
    cols = set(); diag = set(); anti = set()
    def bt(row):
        if row == n: count[0] += 1; return
        for col in range(n):
            if col in cols or (row-col) in diag or (row+col) in anti: continue
            cols.add(col); diag.add(row-col); anti.add(row+col)
            bt(row+1)
            cols.discard(col); diag.discard(row-col); anti.discard(row+col)
    bt(0)
    return count[0]

sequence = [count_queens(n) for n in range(1, 12)]
print('N-Queens counts:', sequence)
# [1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680]

N-Vezir Tahtası Oluşturma

Görüşmeci gerçek tahtaları (LeetCode 51) döndürmenizi istediğinde, her tahtayı queens listesinden oluşturun; burada queens[r], r satırındaki vezirin sütunudur. Dize oluşturma işlemi: her satır için '.' * col + 'Q' + '.' * (n - col - 1). O(n²) olan bu oluşturma işlemi yalnızca özyineleme ağacının yapraklarında (tüm N vezir yerleştirildiğinde) çağrılır; bu nedenle toplam karmaşıklığı etkilemez.

def n_queens_boards(n):
    results = []
    queens = []
    cols = set(); diag = set(); anti = set()
    def build_board():
        return ['.' * c + 'Q' + '.' * (n-c-1) for c in queens]
    def bt(row):
        if row == n:
            results.append(build_board())
            return
        for col in range(n):
            if col in cols or (row-col) in diag or (row+col) in anti: continue
            cols.add(col); diag.add(row-col); anti.add(row+col); queens.append(col)
            bt(row+1)
            cols.remove(col); diag.remove(row-col); anti.remove(row+col); queens.pop()
    bt(0)
    return results

for board in n_queens_boards(4):
    for row in board: print(row)
    print()

Hızlı Kontrol

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

Ders Özeti

Bu derste şunları öğrendiniz: N-Vezir probleminde her satıra bir vezir yerleştirilir ve O(1) kısıt denetimi için sütunlarda, köşegenlerde (satır-sütun) ve karşı köşegenlerde (satır+sütun) kümeler kullanılır; bit maskeleri, kısıt denetimlerini daha da hızlandırır ve tüm yerleşimleri işlem başına yaklaşık O(1) sürede keşfetmeyi sağlar; ayrıca kısıt yayılımı (MRV buluşsal yöntemi), her seferinde en çok kısıtlanan değişkeni seçerek aramayı azaltır. Sırada Açgözlü ve DP yaklaşımlarını karşılaştıracak ve her birini ne zaman uygulayacağınızı öğreneceksiniz.

Başlamak ücretsiz

Yapay zeka eğitmeniyle Python öğren — ücretsiz

Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.

Kurslar
30
Dersler
120

Sıkça Sorulan Sorular

“N-Vezir ve Kısıt Yayılımı” dersi ücretsiz mi?

Evet — “N-Vezir ve Kısıt Yayılımı” 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 DSA Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. DSA Interview Prep kursu toplamda 4 dersten oluşur.

“N-Vezir ve Kısıt Yayılımı” dersinde ne öğreneceğim?

Sütun ve köşegen kümelerini kullanarak kısıtları O(1) sürede kontrol edecek şekilde N×N tahtasına N vezir yerleştirin; çözümleri sayma ile listeleme arasındaki farkı tartışın. DSA 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.

DSA Interview Prep öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te DSA 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 4. dersidir.

“N-Vezir ve Kısıt Yayılımı” 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 DSA Interview Prep dersinde kod yazıp çalıştırabilir miyim?

Evet. Her DSA 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ı
← DSA Interview Prep Sayfasına Dön