Mengenal enam paradigma desain algoritma — brute force, divide & conquer, greedy, dynamic programming, backtracking, dan randomized — serta pola pikir untuk memilih paradigma yang tepat berdasarkan struktur masalah.

Setelah di episode 2 kita menguasai asymptotic analysis dan Master Theorem, pada episode ini kita menarik pandangan ke atas dan memahami paradigma desain algoritma — kerangka berpikir yang menentukan bagaimana kita mendekati sebuah masalah. Memilih paradigma yang tepat sama pentingnya dengan menulis kode yang benar.
Mengapa paradigma penting? Karena masalah yang sama bisa diselesaikan dengan banyak cara. Sebuah masalah bisa di-brute-force (lambat tapi benar), bisa di-greedy (cepat tapi belum tentu optimal), atau di-dynamic-programming (optimal tapi butuh lebih banyak memori). Memahami kapan menggunakan paradigma mana adalah keterampilan inti seorang algorithm engineer.
Brute force adalah pendekatan paling dasar: coba semua kemungkinan solusi, lalu pilih yang terbaik. Ia selalu menghasilkan solusi yang benar, tetapi biasanya terlalu lambat untuk input besar.
# Brute force: cari pasangan dengan jumlah target
def two_sum_brute(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
if nums[i] + nums[j] == target:
return [i, j]Brute force adalah baseline — tolak ukur untuk membandingkan algoritma yang lebih canggih. Jika kalian tidak bisa menulis brute force, kalian belum memahami masalahnya.
Divide & conquer memecah masalah menjadi sub-masalah yang lebih kecil, menyelesaikan masing-masing secara rekursif, lalu menggabungkan hasilnya. Kunci: sub-masalah harus independen.
Contoh: merge sort (bagi array, sort masing-masing, merge), binary search (bagi search space, tentukan sisi mana).
Greedy membuat pilihan lokal optimal di setiap langkah dengan harapan menghasilkan global optimal. Tidak ada retrospeksi — keputusan yang sudah diambil tidak diubah.
Contoh: activity selection (pilih aktivitas yang selesai paling awal), fractional knapsack (ambil item berdasarkan rasio value/weight).
Warning
Greedy tidak selalu menghasilkan solusi optimal. Ia hanya bisa dipakai jika masalah memiliki greedy choice property (pilihan lokal optimal mengarah ke global optimal) DAN optimal substructure (solusi optimal masalah besar mengandung solusi optimal sub-masalah). Tanpa kedua properti ini, greedy akan gagal.
Dynamic programming (DP) adalah generalisasi dari divide & conquer untuk masalah dengan overlapping subproblems — sub-masalah yang sama dihitung berulang kali. DP menyimpan hasil di memo atau tabel agar setiap sub-masalah hanya dihitung sekali.
# Fibonacci dengan DP (memoization)
def fib(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
return memo[n]Tanpa memo, fib(n) membutuhkan Ω(2ⁿ) waktu. Dengan memo, ia menjadi Θ(n) — penghematan eksponensial.
Backtracking mengeksplorasi semua kemungkinan solusi secara sistematis: pilih satu opsi, eksplorasi ke depan, lalu undo (backtrack) jika opsi tersebut tidak mengarah ke solusi. Ini seperti DFS pada pohon keputusan.
Contoh klasik: N-Queens (tempatkan ratu satu per satu, backtrack jika konflik), Sudoku solver, generate semua permutasi.
Randomized algorithms menggunakan keacakan (random number) sebagai bagian dari logikanya. Ada dua kategori:
Pertanyaan kunci saat menghadapi masalah baru:
Coba klasifikasikan masalah berikut ke paradigma yang paling tepat:
| Masalah | Paradigma |
|---|---|
| Sorting array acak (besar) | Divide & conquer (merge sort) |
| Cari target di array terurut | Divide & conquer (binary search) |
| 0/1 Knapsack | Dynamic programming |
| Coin change (minimum koin) | Dynamic programming |
| Shortest path di graph berbobot non-negatif | Greedy (Dijkstra) |
| Generate semua permutasi | Backtracking |
| Cari prime number (sederhana) | Brute force / trial division |
| Fibonacci (n besar) | Dynamic programming |
| Activity selection | Greedy |
| QuickSort dengan random pivot | Randomized |
Tip
Pola ini akan muncul berulang kali di episode selanjutnya. Simpan tabel ini sebagai referensi — saat kalian menghadapi masalah baru, cocokkan dengan pola-pola ini untuk menemukan titik awal pendekatan.
Pada episode 3 ini, kalian telah memahami:
Di episode 4 selanjutnya kita mulai FASE 2: SORTING — membahas Insertion Sort, Selection Sort, dan Merge Sort dengan implementasi, analisis, dan benchmark. Pastikan pemahaman paradigma kalian sudah solid, karena sorting adalah arena pertama kita menerapkannya secara konkret. Sampai jumpa di episode 4!