7  Problem Oturumu 2

Ders 4-5’in uygulaması: master theorem + özyineleme ağacı, sonsuz dizide üstel sıçrama, augmentation ile veri yapısı tasarımı ve two-finger ile O(n)

NotOturum bilgisi

7.1 Bu Problem Oturumu Ne Hakkında?

İkinci problem oturumu, son haftanın konularını uygular: yineleme çözme (master theorem + özyineleme ağacı), arama ve veri yapısı tasarımı. Justin Solomon dört problemi birer “İfade → Yaklaşım → Çözüm → Karmaşıklık” akışıyla işler. Her problemin kazandırdığı taşınabilir araç Şekil 7.1 içinde özetlenir.

Bir genel beceri tüm oturuma damga vurur: problemler çoğu zaman “saçma” bir hikâyeyle (sonsuz taşlar, tuğla üfleyen kurt) sarmalanır; işin ilk adımı işe yarayan iki cümleyi çıkarmaktır. Solomon bunun bir danışmanlık becerisi olduğunu söyler.

“extracting the two words that matter.” — Justin, 1:09:29

İkinci bir uyarı asimptotik gösterim üzerinedir: O, Θ, Ω harflerini özensiz kullanmak en sık yapılan hatadır.

“every single time you write one of those letters down, you should step back 50 feet and look at it and think… did I do that right?” — Justin, 11:54

flowchart TD
    R["Problem Oturumu 2<br/>(Ders 4-5 uygulaması)"] --> P1["Problem 1<br/>Yineleme Çözme"]
    R --> P2["Problem 2<br/>Sonsuz Diziyi Arama"]
    R --> P3["Problem 3<br/>Katmanlı Görüntü Editörü"]
    R --> P4["Problem 4<br/>Tuğla Üfleme"]
    P1 --> T1["Master theorem + ağaç<br/>n^(log_b a) anahtar · 3 durum"]
    P2 --> T2["Üstel sıçrama (galloping)<br/>sınır bul → O(log k)"]
    P3 --> T3["Augmentation<br/>set + sequence birleştir"]
    P4 --> T4["Two-finger<br/>n² → n monoton parmak"]

    classDef root fill:#fef3c7,stroke:#b45309,stroke-width:3px,color:#1f2937
    classDef prob fill:#f3f4f6,stroke:#374151,stroke-width:2px,color:#1f2937
    classDef tool fill:#ffffff,stroke:#9ca3af,stroke-width:1px,color:#1f2937
    class R root
    class P1,P2,P3,P4 prob
    class T1,T2,T3,T4 tool
Şekil 7.1: Problem Oturumu 2’nin kavram haritası: dört problem (üst sıra) ve her birinin öğrettiği taşınabilir araç (alt sıra). Problem 1 master theorem + özyineleme ağacı (n^(log_b a) anahtar nicelik), Problem 2 üstel sıçrama (galloping) ile O(log k) arama, Problem 3 augmentation (set + sequence birleştirme), Problem 4 two-finger ile n² → n indirgemesi kazandırır. Hepsi Ders 4-5 temeline dayanır.

7.2 Problem 1: Yineleme Çözme — Master Theorem ve Özyineleme Ağacı

İfade. \(T(n) = a \cdot T(n/b) + f(n)\) biçimindeki yinelemeleri çöz. Her birini iki yolla yap: (1) master theorem (kural seti), (2) özyineleme ağacı çizip seviye seviye işi toplayarak.

İpucuYaklaşım — Anahtar Niceliği Hesapla, f ile Kıyasla

Master theorem üç duruma ayrılır; anahtar nicelik \(n^{\log_b a}\)’dır (\(a\) = dallanma sayısı, \(b\) = problemin küçülme oranı, \(f\) = düğüm başına iş). Bu niceliğin üssünü (\(\log_b a\)) hesapla, \(f\)’in üssüyle kıyasla, duruma karar ver. Özyineleme ağacı aynı sonucu daha yavaş ama aydınlatıcı biçimde verir; master theorem ise hızlıdır ama “neden”i göstermez.

“the a is kind of like a branching factor… b is the amount that your problem size reduces… f is the amount of work that you do at each node.” — Justin, 6:14

Çözüm. Üç durum:

  • Durum 1: \(f(n) = O(n^{\log_b a - \epsilon})\), \(\epsilon > 0\)\(T(n) = \Theta(n^{\log_b a})\). (\(f\) önemsiz; ağaçta dolaşma baskın.)
  • Durum 2: \(f(n) = \Theta(n^{\log_b a} \cdot \log^k n)\)\(T(n) = \Theta(n^{\log_b a} \cdot \log^{k+1} n)\).
  • Durum 3: \(f(n) = \Omega(n^{\log_b a + \epsilon})\) ve düzenlilik (\(a \cdot f(n/b) \le c \cdot f(n)\), \(c < 1\)) → \(T(n) = \Theta(f(n))\). (\(f\) baskın.)

Örnek (a): \(T(n) = 2T(n/2) + O(\sqrt{n})\). \(a = b = 2\), \(n^{\log_2 2} = n\). \(f = O(\sqrt{n}) = O(n^{1 - 1/2})\), yani \(\epsilon = 1/2 > 0\)Durum 1\(T(n) = \Theta(n)\).

Örnek (b): \(T(n) = 8T(n/4) + O(n^{3/2})\). \(\log_4 8 = 3/2\), yani \(n^{3/2}\). \(f = O(n^{3/2})\), iki taraf eşit → Durum 2, \(k = 0\)\(T(n) = O(n^{3/2}\log n)\). (\(f\) big-O olduğundan sonuç da big-O, big-\(\Theta\) değil.)

Özyineleme ağacı (ikinci yöntem): Ağaçta \(l\). seviyede \(2^l\) (veya \(8^l\)) düğüm var, her biri \(f(n/2^l)\) iş yapar; seviye sayısı \(\log_b n\). Tüm seviyeleri topla — ortaya bir geometrik seri çıkar; sadeleştirince master theorem’le aynı sonuç gelir. Bu iki okumanın görsel karşılaştırması Şekil 7.2’de gösterilir: sol panel ağaç + seviye toplamları, sağ panel 3-durum kararı.

“master theorem… the giant sledgehammer for solving recurrences without understanding why you got the answer.” — Justin, 4:09

Karmaşıklık. Sonuçlar: (a) \(\Theta(n)\), (b) \(O(n^{3/2}\log n)\).

Şekil 7.2: Master teoremini özyineleme ağacıyla okuma: \(T(n)=2T(n/2)+O(\sqrt{n})\) (\(n=64\)). Sol panel: kök (\(l=0\)) tek alt-problem \(\sqrt{n}\); her seviyede düğüm sayısı ikiye katlanır (\(2^l\)) ve her düğümün işi \(\sqrt{n/2^l}\)’e iner. Seviye toplamı \(2^l\cdot\sqrt{n/2^l}\) aşağı indikçe \(\sqrt{2}\) çarpanıyla büyür\(8 \to 11{,}3 \to 16 \to 22{,}6 \to 32 \to 45{,}3 \to 64\) — yani artan bir geometrik seridir ve yapraklar (\(l=6\), amber/BASKIN) baskın terimi verir: \(64\) düğüm \(\times \sqrt{1}=64=\Theta(n)\). Tüm seviyelerin toplamı \(\approx 199{,}2\), ama asimptotik olarak yaprak terimi belirleyicidir → \(\Theta(n)\). Sağ panel: 3-durum karar kuralı — \(f(n)\)’in üssü \(d=\exp(f)=\tfrac12\) ile kritik üs \(c^{*}=\log_b a=\log_2 2=1\) karşılaştırılır. \(d<c^{*}\) olduğundan Durum 1 seçilir (yapraklar baskın, \(\Theta(n^{c^{*}})\)); Durum 2 (\(d=c^{*}\), dengeli) ve Durum 3 (\(d>c^{*}\), kök baskın) burada uygulanmaz. Sonuç: \(\Theta(n)\).

7.3 Problem 2: Sonsuz Diziyi Arama

İfade. Sonsuz bir gezegen dizisinde, indeksi \(k\) olan gezegeni bul. Bir gezegende durup oracle’a sorabilirsin: “aradığım indeks benden büyük mü küçük mü?” Hedef: \(O(\log k)\) zaman (dikkat: \(k\), verinin boyutu değil, aranan indeks).

İpucuYaklaşım — Önce Sağ Sınırı Bul, Sonra İkili Ara

İçgüdü ikili arama; ama ikili arama bir sağ sınır ister ve sonsuz dizide sağ sınır yok. Önce bir sağ sınır bulmalıyız — sonsuz bir kümenin “ortası” yoktur, bu yüzden indeksi her adımda ikiye katlayarak (üstel sıçrama) hedefi aşan ilk gücü buluruz.

“what is the middle of an infinite set of planets? Infinite, exactly. It’s a problem.” — Justin, 49:26

Çözüm. İki aşama:

  1. Sınır bul (üstel sıçrama): \(m = 0, 1, 2, \dots\) için \(2^m\) indeksli gezegeni ziyaret et, ta ki \(k \le 2^m\) olana dek. Bu, \(\log k\) adım sürer ve şu sandviçi verir: \(2^{m-1} \le k \le 2^m\).
  2. İkili arama: Artık \([2^{m-1}, 2^m]\) aralığı var (genişliği \(\sim k\)); bu aralıkta ikili arama, \(\log k\) adım.

“I’m going to visit planet 2 to the m for each m starting with m equals 0.” — Justin, 50:25

Şekil 7.3 bu iki aşamayı tek bir sayı-doğrusunda izler: önce galloping yaylarıyla sınır, sonra numaralı mid sorgularıyla ikili arama.

Karmaşıklık. \(\log k\) (sınır bulma) + \(\log k\) (ikili arama) = \(O(\log k)\).

7.4 Problem 3: Katmanlı Görüntü Editörü

İfade. Bir görüntü editörü veri yapısı tasarla: katmanları üst-alt sırada tutar. İşlemler: make_doc \(O(1)\), import(x) (üste ekle) \(O(n)\), display() (sırayla tüm ID’ler) \(O(n)\), ve move_below(x, y) (\(x\) katmanını \(y\)’nin altına taşı) \(O(\log n)\).

İpucuYaklaşım — İki Yönü Ayır, Sonra Augmentation ile Bağla

Problemde iki yön var: dizi (sequence) yönü (display sırası) ve küme (set) yönü (bir katmanı hızlı bulmak). İkisini ayrı veri yapısıyla çöz, sonra bir augmentation ile bağla — sıralı dizideki her anahtara, bağlı listedeki düğümün işaretçisini iliştir. Böylece “bul” \(O(\log n)\), “yeniden bağla” \(O(1)\) olur.

Çözüm. İki yapı birlikte çalışır:

  • Çift bağlı liste (doubly linked list): katmanların ekran sırasını tutar (display için \(O(n)\)).
  • Sıralı dizi (set): ID’leri sıralı tutar; ikili aramayla bir ID’yi \(O(\log n)\)’de bulur.
  • Augmentation: sıralı dizideki her anahtara, o öğenin bağlı listedeki düğümüne bir işaretçi ekle. (Bir düğümü silmek diğer işaretçileri bozmaz — işaretçiler geçerli kalır.)

“we can attach data to our keys… I am going to attach a pointer into my linked list.” — Justin, 1:02:21

move_below(x, y) üç adım: (1) \(x\) ve \(y\)’yi sıralı dizide ikili aramayla bul, bağlı liste işaretçilerini al — \(O(\log n)\); (2) \(x\)’i bağlı listeden çıkar ve \(y\)’nin altına ekle — işaretçiler elimizde olduğundan \(O(1)\); (3) küme değişmez (sadece sıra değişti). Önemli sağlama: move_below kümeyi değiştirmez, çünkü hangi öğelerin olduğu değil, yalnızca sıraları değişir.

Karmaşıklık. make_doc \(O(1)\), import \(O(n)\) (sıralı diziye ekleme), display \(O(n)\), move_below \(O(\log n)\) (bulma) + \(O(1)\) (yeniden bağlama).

7.5 Problem 4: Tuğla Üfleme

İfade. Bir sıra evin tuğla sayıları verilir. Kurt bir eve üfleyince o ev ve sağındaki kendisinden az tuğlalı tüm evler yıkılır. Her ev için, ona üflendiğinde kaç ev yıkıldığını hesapla. (Hikâyenin özü: “her öğe için, sağında kendisinden küçük olanları say + 1”.)

İpucuYaklaşım — Naif Çift Döngüden Monoton Parmaklara

Naif çözüm çift döngü → \(O(n^2)\); yasak. Bir yapısal varsayım kullanılır: bir ev hariç hepsi özel (sağ komşusu kendisinden büyük-eşit), yani dizi artan-sonra-bir-düşüş-sonra-artan iki sıralı parçaya bölünür. Sol yarı (artan) sağa hiçbir şey yıkamaz; her ev yalnızca sağ yarıda kendinden küçükleri yıkar. Sol yarıdaki ev büyüdükçe yıkılan aralık yalnız genişler — geri gitmez — ve bu, two-finger’a kapı açar.

Çözüm. Sol yarıdaki ev tuğla sayısı arttıkça, sağ yarıda yıkılan evlerin aralığı yalnızca büyür (geri gitmez). Bu, iki parmak (two-finger) tekniğine kapı açar: i parmağı sol yarıda ilerlerken, j parmağı sağ yarıda “ilk yıkılmayan” evi işaret eder; i sağa kaydıkça j de sağa kayar, asla sola dönmez.

“It’s called a two-finger algorithm.” — Justin, 1:25:02

j = right_start                              # sağ yarının ilk evi (global indeks)
for i in range(left_end + 1):
    while j < n and heights[j] < heights[i]:
        j += 1                               # j asla geri gitmez (5→6→7→8)
    smaller = j - right_start                # sağda i'den küçük ev sayısı
    damage[i] = 1 + smaller                  # kendisi + sağda küçük ev sayısı

Her iki parmak da diziyi yalnızca bir kez kateder → \(O(n)\). (Genel hâl, özel varsayım olmadan, aynı fikir + merge sort ile çözülür.) Şekil 7.4 bu izi \([2,4,6,9]\) sol yarısı ile \([1,3,5,7]\) sağ yarısı üzerinde adım adım gösterir; j parmağının \(5 \to 6 \to 7 \to 8\) ile yalnız sağa kaydığına dikkat.

Karmaşıklık. Two-finger ile \(O(n)\) (\(n^2\) naif veya \(n\log n\) ikili-arama yerine).

Şekil 7.4: İki parmak (two-finger) tuğla üfleme izi — Problem 4 İMZA figürü. Dizi tek düşüşten (9→1) ikiye ayrılır: sol yarı [2,4,6,9] artan, sağ yarı [1,3,5,7] artan. Sol parmak i sol yarıyı soldan sağa sweep eder (amber, eşik = heights[i]); sağ parmak j sağ yarıda eşikten küçük olmayan ilk evi işaretler. i sağa kaydıkça eşik büyür, bu yüzden j yalnız sağa kayar — asla geri gitmez (5→6→7→8). Adım 1 (eşik 2): sağda yalnız 1 küçük → hasar 2. Adım 2 (eşik 4): 1,3 küçük → hasar 3. Adım 3 (eşik 6): 1,3,5 → hasar 4. Adım 4 (eşik 9): 1,3,5,7 → hasar 5. Yıkılan sağ-yarı evleri her satırda koyu amber. İki parmak diziyi birer kez katettiği için toplam O(n) — naif “her ev için sağı tara” O(n²) yerine. Sağ yarının kendi içi de artan olduğundan oradaki her ev yalnız kendini yıkar (hasar 1); nihai hasar[] = [2,3,4,5,1,1,1,1].

7.6 Ne Öğrendik?

ÖnemliAltı Taşınabilir Araç

Bu oturum, Ders 4-5’in teorisini dört somut problemde uyguladı ve altı taşınabilir araç kazandırdı:

  1. Master theorem + özyineleme ağacı: Yinelemeyi iki yolla çöz; \(n^{\log_b a}\) anahtar niceliktir, ağaç “neden”i gösterir.
  2. Asimptotik titizlik: \(O\) / \(\Theta\) / \(\Omega\)’yu özensiz yazma; \(f\) big-O ise sonuç da big-O’dur.
  3. Üstel sıçrama (galloping): Sağ sınırı olmayan aramada, \(2^m\) ile sınır bul, sonra ikili ara — \(O(\log k)\).
  4. Augmentation ile iki yapı birleştirme: set (ID bul) + sequence (sıra tut); anahtara liste işaretçisi ekle.
  5. Two-finger ile \(n^2 \to n\): Monoton ilerleyen iki parmak, çift döngüyü lineere indirir.
  6. Problem okuma: Süslü hikâyeden “işe yarayan iki cümleyi” çıkarmak — algoritmik özü görmek.

7.7 Sonraki

UyarıDers 5 (L5) — Doğrusal Zamanlı Sıralama

Sırada Ders 5 (L5): Doğrusal Zamanlı Sıralama var — Jason Ku ile, karşılaştırma modelinin \(\Omega(n \log n)\) sınırını aşan sıralamalara (counting sort, radix sort) geçiyoruz. Bu oturumdaki master theorem ve two-finger sezgileri, oradaki doğrusal-zaman analizinde doğrudan işine yarayacak.