Böl ve Yönet Şablonu
Birleştirmeli sıralamadan üç adımlı şablonu (böl, yönet, birleştir) çıkarın ve yeni problem biçimlerine sistematik olarak uygulayın.
Böl ve Yönet Şablonu, CoddyKit'te ücretsiz bir DSA Interview Prep dersidir. Bu, 4 dersinin 1. 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.
Böl ve Yönet Nedir?
Böl ve Yönet, bir problemi aynı türden bağımsız alt problemlere ayırarak, her birini özyinelemeli biçimde çözerek ve çözümlerini birleştirerek çözer. Buradaki kilit sözcük bağımsız sözcüğüdür — alt problemler, üst üste bindikleri DP'nin aksine, durumu paylaşmaz. Klasik örnekler arasında merge sıralaması, ikili arama, hızlı sıralama, en yakın nokta çifti ve hızlı matris çarpımı bulunur. Böl ve Yönet, üç adımlı şablon sayesinde genellikle O(n log n) zaman elde eder.
# Divide and Conquer vs DP:
# D&C: sub-problems are INDEPENDENT (no overlap)
# DP: sub-problems OVERLAP (same sub-problem solved multiple times)
# D&C examples:
# Merge sort: split array in half, sort each, merge
# Binary search: check midpoint, recurse on one half
# Max subarray (D&C): find max in left half, right half, crossing
# Recurrence pattern:
# T(n) = 2T(n/2) + O(n) → O(n log n) [merge sort]
# T(n) = T(n/2) + O(1) → O(log n) [binary search]
# T(n) = T(n/k) + O(n) → O(n log_k n) [k-way split]Üç Adımlı Şablon
Her Böl ve Yönet algoritması üç adımı izler: (1) Böl — problemi, genellikle orta noktadan, iki veya daha fazla küçük alt probleme ayırın. (2) Çöz — her alt problemi özyinelemeli olarak çözün. Özyinelemeyi durdurmak için bir taban durumu tanımlayın (genellikle n ≤ 1). (3) Birleştir — alt problemlerin çözümlerini genel çözümde birleştirin. Yaratıcılık tamamen Birleştir adımında ortaya çıkar; Böl adımı genellikle yalnızca orta noktadan ayırmadan ibarettir.
def divide_and_conquer(arr, lo, hi):
# BASE CASE: trivial sub-problem
if lo >= hi:
return base_case_result(arr, lo, hi)
# DIVIDE: split at midpoint
mid = (lo + hi) // 2
# CONQUER: solve sub-problems recursively
left_result = divide_and_conquer(arr, lo, mid)
right_result = divide_and_conquer(arr, mid + 1, hi)
# COMBINE: merge results
return combine(left_result, right_result, arr, lo, mid, hi)
def base_case_result(arr, lo, hi): return arr[lo]
def combine(l, r, arr, lo, mid, hi): return max(l, r)Temel Örnek Olarak Merge Sıralaması
Merge sıralaması, Böl ve Yönet'i mükemmel biçimde gösterir: Diziyi orta noktadan bölün. Her iki yarıyı özyinelemeli olarak sıralayarak çözün. Sıralanmış iki yarıyı O(n) içinde birleştirerek birleştirin. Tüm iş birleştirme adımında gerçekleşir. Özyineleme bağıntısı: T(n) = 2T(n/2) + O(n). Ana Teorem'in 2. durumuna göre: T(n) = O(n log n). Bu, ezberlenmesi gereken en önemli Böl ve Yönet özyineleme bağıntısıdır.
def merge_sort(arr):
# BASE CASE
if len(arr) <= 1:
return arr
# DIVIDE
mid = len(arr) // 2
# CONQUER
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
# COMBINE
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]); i += 1
else:
result.append(right[j]); j += 1
return result + left[i:] + right[j:]
print(merge_sort([5, 3, 8, 1, 9, 2])) # [1,2,3,5,8,9]Ana Teorem için Hızlı Başvuru
Ana Teorem, T(n) = aT(n/b) + f(n) biçimindeki özyineleme bağıntılarını çözer: 1. Durum: f(n) = O(n^(log_b(a) - ε)) → T(n) = O(n^log_b(a)). 2. Durum: f(n) = O(n^log_b(a)) → T(n) = O(n^log_b(a) × log n). 3. Durum: f(n) = Ω(n^(log_b(a) + ε)) → T(n) = O(f(n)). Merge sıralaması: a=2, b=2, f(n)=O(n), n^log_2(2)=n → 2. Durum → O(n log n).
# Master Theorem quick examples:
# T(n) = 2T(n/2) + O(n) → a=2,b=2,f=n,n^log2(2)=n → Case2 → O(n log n)
# T(n) = 2T(n/2) + O(1) → a=2,b=2,f=1,n^1=n >> 1 → Case1 → O(n)
# T(n) = 2T(n/2) + O(n^2) → a=2,b=2,f=n^2,n^1 << n^2 → Case3 → O(n^2)
# T(n) = T(n/2) + O(1) → a=1,b=2,f=1,n^log2(1)=1=f → Case2 → O(log n)
# T(n) = T(n/3)+T(2n/3)+O(n) → Master doesn't apply directly → O(n log n) by recursion tree
recurrences = [
('Merge sort: 2T(n/2)+n', 'O(n log n)'),
('Binary search: T(n/2)+1', 'O(log n)'),
('Naive matrix mult: 8T(n/2)+n^2', 'O(n^3)'),
('Strassen: 7T(n/2)+n^2', 'O(n^2.81)'),
]
for r, sol in recurrences: print(r, '->', sol)Maksimum Alt Dizi: Böl ve Yönet Yaklaşımı
Maksimum alt dizi için Böl ve Yönet yaklaşımında yanıt ya tamamen sol yarıdadır, ya tamamen sağ yarıdadır ya da orta noktanın üzerinden geçer. Orta noktadan geçen durum için ortadan sola ve ortadan sağa doğru genişleyin; her yöndeki maksimum toplamı alın ve ardından birleştirin. Bu O(n log n) Böl ve Yönet yaklaşımı, Kadane algoritmasının O(n) yaklaşımından daha yavaştır; ancak şablonu çok iyi gösterir ve Böl ve Yönet hakkında yaygın bir mülakat sorusudur.
def max_subarray_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
# Conquer
left_max = max_subarray_dc(nums, lo, mid)
right_max = max_subarray_dc(nums, mid + 1, hi)
# Cross-midpoint sum
left_sum = curr = 0
for i in range(mid, lo - 1, -1):
curr += nums[i]
left_sum = max(left_sum, curr)
right_sum = curr = 0
for i in range(mid + 1, hi + 1):
curr += nums[i]
right_sum = max(right_sum, curr)
cross_max = left_sum + right_sum
return max(left_max, right_max, cross_max)
nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(max_subarray_dc(nums)) # 6Kuvvet Fonksiyonu: Hızlı Üs Alma
Hızlı Üs Alma (LeetCode 50): Böl ve Yönet kullanarak x^n değerini O(log n) içinde hesaplayın. n çiftse: x^n = (x^(n/2))^2. n tekse: x^n = x × x^(n-1). Negatif n değerini x^(-n) = 1/x^n ile ele alın. Her özyinelemeli çağrıda n yarıya indiğinden derinlik O(log n) olur. Bu, Birleştir adımının yalnızca çarpma olduğu; basit ama etkili, temiz bir örnektir.
def my_pow(x, n):
if n < 0:
return 1 / my_pow(x, -n)
# BASE CASE
if n == 0: return 1
# DIVIDE and CONQUER
half = my_pow(x, n // 2)
if n % 2 == 0:
return half * half # even: x^n = (x^(n/2))^2
else:
return x * half * half # odd: x^n = x * (x^(n/2))^2
print(my_pow(2, 10)) # 1024
print(my_pow(2, -2)) # 0.25
print(my_pow(3, 5)) # 243
print(my_pow(0, 0)) # 1Sıralı Diziden BST'ye
Sıralı Diziyi BST'ye Dönüştürme (LeetCode 108), Böl ve Yönet kullanır: yüksekliğin dengeli olmasını sağlamak için orta noktayı kök olarak seçin; sol alt ağacı sol yarıdan, sağ alt ağacı da sağ yarıdan özyinelemeli olarak oluşturun. Bu işlem, minimum yüksekliği O(log n) olan, yüksekliği dengeli bir BST üretir. Böl ve Yönet yapısı ikili aramayı yansıtır — özyinelemenin her düzeyi, geçerli alt aralığın orta noktasını kök olarak atar.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def sorted_array_to_bst(nums):
def helper(lo, hi):
if lo > hi: return None
mid = (lo + hi) // 2
node = TreeNode(nums[mid]) # DIVIDE at midpoint
node.left = helper(lo, mid - 1) # CONQUER left
node.right = helper(mid + 1, hi) # CONQUER right
# COMBINE: already done by assignment
return node
return helper(0, len(nums) - 1)
def inorder(node):
if not node: return []
return inorder(node.left) + [node.val] + inorder(node.right)
root = sorted_array_to_bst([-10, -3, 0, 5, 9])
print(inorder(root)) # [-10,-3,0,5,9] (sorted, proving BST property)Böl ve Yönet Ne Zaman En İyi Seçim Değildir
Böl ve Yönet'in ek yükleri vardır: işlev çağrısı yığını derinliği, dizi dilimleme (indeksler kullanılmıyorsa) ve birleştirme adımı. Birleştirme adımı O(n) veya daha ucuz olduğunda en iyi seçenektir. Alt problemler örtüştüğünde Böl ve Yönet çözümleri gereksiz yere yeniden hesaplar; bu durumda DP gerekir. Birleştirme adımı baskın olduğunda (örneğin O(n²)), Böl ve Yönet naif yaklaşımlara kıyasla iyileşme sağlamaz. Ne zaman hangisini seçeceğinizi bilin: bağımsız alt problemler için Böl ve Yönet, örtüşen alt problemler için DP.
# When D&C hurts:
# Fibonacci with pure D&C (no memo): T(n) = T(n-1) + T(n-2) → O(2^n)
# Sub-problems OVERLAP → use DP or memoisation instead
def fib_dc(n):
if n <= 1: return n
return fib_dc(n-1) + fib_dc(n-2) # O(2^n)!
def fib_dp(n):
a, b = 0, 1
for _ in range(n): a, b = b, a+b
return a # O(n)
print(fib_dp(30)) # fast
# fib_dc(40) would take seconds — do not run large values!Sıralı Matriste İkili Arama için Böl ve Yönet
Her satırı ve sütunu sıralı olan 2B bir matriste arama (LeetCode 240), Böl ve Yönet ile çözülebilir: sağ üst köşeden başlayın. Geçerli değer hedeften büyükse sola gidin (sütunu elersiniz). Geçerli değer hedeften küçükse aşağı gidin (satırı elersiniz). Eşitse değeri bulmuş olursunuz. Bu O(m+n) algoritması teknik olarak özyinelemeli bir Böl ve Yönet yöntemi değildir; ancak her adımda arama uzayının yarısını eleme şeklindeki temel fikri paylaşır.
def search_matrix(matrix, target):
if not matrix: return False
m, n = len(matrix), len(matrix[0])
row, col = 0, n - 1 # start top-right
while row < m and col >= 0:
val = matrix[row][col]
if val == target:
return True
elif val > target:
col -= 1 # eliminate this column
else:
row += 1 # eliminate this row
return False
matrix = [
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
print(search_matrix(matrix, 5)) # True
print(search_matrix(matrix, 20)) # FalseÖzyineleme Ağacı Analizi
Ana Teorem'e uymayan Böl ve Yönet özyineleme bağıntıları için özyineleme ağacı yöntemini kullanın. Özyinelemeli çağrıların her düzeyini çizin ve düzey başına yapılan işi toplayın. Merge sıralamasında k düzeyinde, her biri n/2^k boyutunda 2^k alt problem vardır. Düzey başına iş = 2^k × O(n/2^k) = O(n). Toplam düzey sayısı = log n. Toplam iş = O(n log n). Bu görsel yöntem her özyineleme bağıntısında işe yarar ve Böl ve Yönet'in genellikle neden O(n log n) değerine ulaştığına dair sezgi oluşturur.
# Merge sort recursion tree analysis:
# Level 0: 1 problem of size n → O(n) work
# Level 1: 2 problems of size n/2 → 2*O(n/2) = O(n) work
# Level 2: 4 problems of size n/4 → 4*O(n/4) = O(n) work
# ...
# Level log(n): n problems of size 1 → n*O(1) = O(n) work
# Total levels = log(n)+1
# Total work = O(n) * O(log n) = O(n log n)
import math
n = 64
levels = int(math.log2(n)) + 1
print(f'n={n}: {levels} levels, {n}*{levels} = {n*levels} work units')
print(f'O(n log n) = O({n} * {int(math.log2(n))}) = O({n*int(math.log2(n))})')Mülakatta Böl ve Yönet Çözümünü Anlatma
Bir mülakatta Böl ve Yönet çözümünü sunarken: (1) Üç adımı açıkça belirtin: 'Orta noktadan bölecek, her yarıyı özyinelemeli olarak çözecek ve ardından birleştirerek bir araya getireceğim.' (2) Taban durumunu net biçimde belirleyin. (3) Özyineleme bağıntısını türetin: T(n) = 2T(n/2) + O(n). (4) O(n log n) sonucunu elde etmek için Ana Teorem'i veya özyineleme ağacını uygulayın. (5) Böl ve Yönet'in alternatiflerden ne zaman daha iyi veya daha kötü olduğunu belirtin (örtüşen alt problemler için DP, maksimum alt dizi için Kadane algoritması).
# D&C interview template to memorize:
def dc_template(problem, lo, hi):
# 1. BASE CASE (state it first)
if lo == hi: return solve_base(problem, lo)
# 2. DIVIDE
mid = (lo + hi) // 2
# 3. CONQUER
left = dc_template(problem, lo, mid)
right = dc_template(problem, mid + 1, hi)
# 4. COMBINE (this is where the algorithm-specific logic goes)
return combine_results(left, right, problem, lo, mid, hi)
def solve_base(p, i): return p[i]
def combine_results(l, r, p, lo, mid, hi): return max(l, r)
print('D&C template: base-divide-conquer-combine')
print('Complexity usually: T(n)=2T(n/2)+O(n) → O(n log n)')Hızlı Kontrol
Bu dersteki Veri Yapıları ve Algoritmalar — Kodlama Mülakatına Hazırlık kavramlarını anlayıp anlamadığınızı sınayın.
Ders Özeti
Bu derste şunları öğrendiniz: Böl ve Yönet şu şablonu izler: taban durumu → orta noktadan böl → özyinelemeli olarak çöz → birleştir, T(n) = 2T(n/2) + O(n), Ana Teorem'in 2. Durumu ile O(n log n) sonucunu verir ve Böl ve Yönet bağımsız alt problemler için en uygunudur; alt problemler örtüştüğünde DP gerekir. Sırada, değiştirilmiş bir merge sıralaması kullanarak bir dizideki inversiyonları saymak için Böl ve Yönet'i uygulayacağız.
Sıkça Sorulan Sorular
“Böl ve Yönet Şablonu” dersi ücretsiz mi?
Evet — “Böl ve Yönet Şablonu” 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.
“Böl ve Yönet Şablonu” dersinde ne öğreneceğim?
Birleştirmeli sıralamadan üç adımlı şablonu (böl, yönet, birleştir) çıkarın ve yeni problem biçimlerine sistematik olarak uygulayı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 1. dersidir.
“Böl ve Yönet Şablonu” 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
- 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ı