Greedy vs DP: Kapan Menggunakan Masing-Masing
Identifikasi ciri-ciri masalah yang dapat diselesaikan secara greedy dibandingkan masalah yang memerlukan DP menggunakan sifat pilihan greedy dan argumen pertukaran
Greedy vs DP: Kapan Menggunakan Masing-Masing adalah pelajaran DSA Interview Prep gratis di CoddyKit. Ini adalah pelajaran 1 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar DSA Interview Prep, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus DSA Interview Prep mencakup 4 pelajaran total.
Ikhtisar Serakah dan DP
Pendekatan Serakah dan Pemrograman Dinamis sama-sama menyelesaikan masalah optimisasi — mencari susunan maksimum, minimum, atau optimal. Pendekatan serakah membuat pilihan optimal secara lokal pada setiap langkah tanpa meninjau ulang keputusan sebelumnya. DP mengeksplorasi semua kemungkinan, tetapi menggunakan memoization untuk menghindari perhitungan ulang. Mengetahui pendekatan mana yang harus digunakan dapat menghemat waktu berjam-jam untuk menelusuri kesalahan pada pendekatan serakah yang keliru atau tabel DP yang rumit dan tidak perlu.
# Greedy: always take the locally best option
# Example: coin change with coins [1, 5, 10, 25]
# Greedy: take as many 25s as possible, then 10s, etc.
# This works for standard denominations but NOT all coin sets!
# DP: explore all possibilities via memoisation
# Example: coin change with coins [1, 3, 4] and target 6
# Greedy would pick 4, then 1, 1 → 3 coins
# DP finds: 3 + 3 → 2 coins (optimal!)
print('Greedy can fail when local optimum != global optimum')Sifat Pilihan Serakah
Suatu masalah memiliki sifat pilihan serakah ketika solusi optimal secara global selalu dapat dibangun melalui pilihan yang optimal secara lokal (serakah). Secara formal: terdapat solusi optimal yang diawali oleh pilihan serakah, sehingga kita tidak pernah perlu melakukan penelusuran mundur. Pembuktiannya biasanya menggunakan argumen pertukaran: anggap suatu solusi optimal tidak mencakup pilihan serakah, lalu tunjukkan bahwa pilihan tersebut dapat ditukar masuk tanpa memperburuk hasil.
# Exchange argument example: Activity Selection
# Greedy: always pick the activity that ends earliest
# Proof: suppose optimal solution starts with activity A (not earliest-ending)
# Let G be the earliest-ending activity.
# Replace A with G in the solution:
# - G ends no later than A, so G does not conflict with any activity A allowed
# - The solution remains valid with at least as many activities
# Therefore greedy choice (earliest end) is always safe.
activities = [(1,4), (3,5), (0,6), (5,7), (3,9), (5,9), (6,10), (8,11), (8,12), (2,14)]
activities.sort(key=lambda x: x[1]) # sort by end time
print('Sorted by end:', activities[:4], '...')Substruktur Optimal
Pendekatan serakah dan DP sama-sama memerlukan substruktur optimal: solusi optimal untuk masalah secara keseluruhan memuat solusi optimal untuk submasalahnya. Perbedaannya terletak pada apakah solusi submasalah yang optimal dapat ditentukan secara serakah (tanpa mengeksplorasi semua pilihan) atau harus ditentukan dengan membandingkan beberapa pilihan. Jika Anda membuat sebuah pilihan dan submasalah yang tersisa memiliki struktur yang sama, pendekatan serakah dapat digunakan. Jika Anda harus membandingkan beberapa pilihan, gunakan DP.
# Greedy works: activity selection
# Making the greedy choice (earliest-ending) leaves a sub-problem
# that is structurally identical (activity selection on remaining activities)
# and the greedy choice for the sub-problem is still valid.
# DP needed: 0/1 knapsack
# After choosing to include/exclude item i, the remaining sub-problem
# depends on WHICH item we chose — different choices yield different sub-problems.
# No single greedy rule works for all inputs.
print('Greedy: sub-problem is unique after each choice')
print('DP: sub-problem depends on which choice was made')Indikasi Submasalah yang Saling Tumpang Tindih untuk DP
Jika submasalah yang sama diselesaikan beberapa kali dalam dekomposisi rekursif, diperlukan DP dengan memoization. Gambarkan pohon rekursi dan cari simpul yang berulang. Untuk Fibonacci, fib(3) dihitung dua kali dalam pohon untuk fib(5). Untuk penukaran koin dengan koin [1,3,4] dan sasaran 6: submasalah untuk sasaran 3, 2, dan 1 muncul beberapa kali. Submasalah yang saling tumpang tindih ditambah substruktur optimal = DP.
# Recursion tree for coin change [1,3,4], target=6
# bt(6) → bt(5) → bt(4) → bt(3) (repeated!)
# → bt(2) → bt(1) (repeated!)
# → bt(3) (repeated!)
# → bt(2) (repeated!)
# Without memoisation: exponential time
# With DP table: O(target * len(coins)) time
def coin_change_dp(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for a in range(1, amount + 1):
for c in coins:
if c <= a:
dp[a] = min(dp[a], dp[a - c] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
print(coin_change_dp([1, 3, 4], 6)) # 2 (3+3)
print(coin_change_dp([2], 3)) # -1 (impossible)Masalah Serakah Klasik
Masalah-masalah yang kebenarannya dapat dibuktikan dengan pendekatan serakah: (1) Penjadwalan Aktivitas/Interval — pendekatan serakah berdasarkan waktu selesai paling awal. (2) Pohon Rentang Minimum — algoritma Prim dan Kruskal. (3) Pengodean Huffman — selalu gabungkan dua simpul dengan frekuensi terendah. (4) Ransel Fraksional — ambil item berdasarkan rasio nilai/berat tertinggi. (5) Permainan Lompatan — lacak indeks maksimum yang dapat dicapai. Semua masalah ini memiliki pembenaran melalui argumen pertukaran.
# Fractional Knapsack: greedy works
def fractional_knapsack(items, capacity):
# Sort by value/weight ratio descending
items.sort(key=lambda x: x[1]/x[0], reverse=True)
total = 0
for weight, value in items:
if capacity <= 0: break
take = min(weight, capacity)
total += take * (value / weight)
capacity -= take
return total
items = [(10, 60), (20, 100), (30, 120)] # (weight, value)
print(fractional_knapsack(items, 50)) # 240.0
# 0/1 Knapsack: greedy FAILS
# Must use DP (can't take fractions)Saat Serakah Gagal: Kontrapontoh
Menemukan kontrapontoh merupakan cara tercepat untuk membantah hipotesis serakah. Untuk penukaran koin dengan koin [1, 3, 4] dan sasaran 6: pendekatan serakah (terbesar lebih dahulu) mengambil 4, lalu 1+1 = 3 koin. DP menemukan 3+3 = 2 koin. Untuk ransel 0/1: pendekatan serakah berdasarkan rasio mengambil item dengan rasio terbaik, tetapi mungkin melewatkan kombinasi yang mengisi kapasitas dengan lebih baik. Jika Anda dapat membuat kontrapontoh dalam waktu kurang dari satu menit, beralihlah ke DP.
# Counterexample: coin change with non-standard coins
def greedy_coins(coins, amount):
coins.sort(reverse=True)
count = 0
for c in coins:
while amount >= c:
amount -= c
count += 1
return count if amount == 0 else -1
def dp_coins(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for a in range(1, amount + 1):
for c in coins:
if c <= a: dp[a] = min(dp[a], dp[a-c] + 1)
return dp[amount] if dp[amount] < float('inf') else -1
coins, target = [1, 3, 4], 6
print('Greedy:', greedy_coins(coins[:], target)) # 3 (4+1+1)
print('DP: ', dp_coins(coins, target)) # 2 (3+3)Tabel Perbandingan: Serakah vs DP
Perbedaan utama secara berdampingan: Kompleksitas waktu — pendekatan serakah biasanya O(n log n) (didominasi oleh pengurutan); DP adalah O(n × keadaan). Kompleksitas ruang — pendekatan serakah menggunakan O(1) ruang tambahan; DP menggunakan O(keadaan). Kebenaran — pendekatan serakah memerlukan pembuktian; DP selalu benar jika keadaan dan relasinya tepat. Penerapan — pendekatan serakah untuk penjadwalan, pohon rentang, dan Huffman; DP untuk ransel, penyelarasan urutan, dan jalur terpendek dengan bobot negatif.
# Performance comparison
import time
def time_it(func, *args):
start = time.time()
result = func(*args)
return result, time.time() - start
# Large coin change test
coins = [1, 5, 10, 25, 100]
amount = 10000
def dp_coins(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for a in range(1, amount + 1):
for c in coins:
if c <= a: dp[a] = min(dp[a], dp[a-c]+1)
return dp[amount]
result, elapsed = time_it(dp_coins, coins, amount)
print(f'DP coin change(amount={amount}): {result} coins in {elapsed:.4f}s')Kerangka Pengambilan Keputusan
Alur keputusan wawancara: (1) Dapatkah Anda membuktikan sifat pilihan serakah dengan argumen pertukaran? Jika ya → gunakan pendekatan serakah. (2) Apakah submasalahnya saling tumpang tindih (keadaan yang sama dicapai melalui beberapa cara)? Jika ya → gunakan DP. (3) Apakah masalah meminta Anda menghitung jumlah atau mencantumkan semua solusi? → gunakan DP atau penelusuran mundur. (4) Apakah masalah meminta satu nilai optimal dengan pengurutan alami? Pertimbangkan pendekatan serakah. (5) Jika ragu, tuliskan DP — pendekatan ini selalu benar jika relasinya tepat, meskipun lebih lambat.
# Decision questions to ask:
questions = [
'1. Is there a natural ordering (by time, ratio, size)?',
'2. Does making the greedy choice leave a smaller same-type problem?',
'3. Can I construct a counterexample quickly?',
'4. Are sub-problems reused across different choice sequences?',
'5. Does the problem involve counting or listing (not just optimising)?',
]
for q in questions:
print(q)
print()
print('Greedy signals: scheduling, spanning tree, Huffman, jump game')
print('DP signals: knapsack, edit distance, LCS, coin change (general)')Masalah Interval: Serakah vs DP
Masalah interval terbagi antara pendekatan serakah dan DP. Interval yang tidak saling tumpang tindih (hapus sesedikit mungkin): urutkan berdasarkan waktu selesai, lalu secara serakah ambil interval — pendekatan serakah terbukti optimal. Penjadwalan interval berbobot (maksimalkan bobot total): diperlukan DP karena interval yang berat dapat bertumpang tindih dengan banyak interval ringan, sehingga semua himpunan valid perlu dibandingkan. Faktor pembeda adalah apakah semua interval memiliki bobot yang sama (serakah) atau bobot yang bervariasi (DP).
# Non-overlapping intervals: greedy works
def erase_overlap_intervals(intervals):
if not intervals: return 0
intervals.sort(key=lambda x: x[1])
count = 0
last_end = float('-inf')
for start, end in intervals:
if start >= last_end:
last_end = end # keep this interval
else:
count += 1 # remove this interval
return count
print(erase_overlap_intervals([[1,2],[2,3],[3,4],[1,3]])) # 1
print(erase_overlap_intervals([[1,2],[1,2],[1,2]])) # 2Mengenali Indikasi Masalah
Indikasi umum dalam pernyataan masalah: ‘jumlah operasi minimum’, ‘keuntungan maksimum’, ‘pemilihan optimal’ → dapat diselesaikan dengan pendekatan serakah atau DP, periksa apakah ada tumpang tindih. ‘hitung jumlah cara’ → selalu gunakan DP. ‘temukan jadwal valid apa pun’ → mungkin dapat diselesaikan dengan pendekatan serakah. ‘semua kemungkinan’ → penelusuran mundur. ‘tidak dapat mengambil yang bersebelahan’ → DP (perampokan rumah). ‘rapat, interval, tugas’ → kemungkinan besar pendekatan serakah. Memetakan indikasi ke keluarga algoritma mempercepat diagnosis masalah wawancara.
# Signal-to-algorithm mapping
signals = {
'minimum steps/coins/operations': 'DP (unless trivially greedy)',
'maximum profit/value with constraint': 'DP (knapsack family)',
'count ways to reach/achieve': 'DP (always)',
'all combinations/permutations': 'Backtracking',
'schedule tasks within time': 'Greedy (sort by deadline/end)',
'cannot pick adjacent': 'DP (house robber pattern)',
'free to pick any subset': 'DP or Greedy (check overlap)',
'interval merging/selecting': 'Greedy (sort by end time)',
}
for signal, algo in signals.items():
print(f'{signal!r}: → {algo}')Membuktikan Kebenaran Serakah
Untuk membuktikan algoritma serakah benar, gunakan argumen pertukaran: (1) Anggap terdapat solusi optimal OPT yang berbeda dari solusi serakah G pada pilihan pertama. (2) Tunjukkan bahwa Anda dapat menukar pilihan serakah ke dalam OPT tanpa meningkatkan nilai tujuan. (3) Berdasarkan induksi, solusi serakah sama baiknya dengan solusi optimal mana pun. Dalam wawancara, Anda tidak memerlukan pembuktian lengkap, tetapi menjelaskan intuisi argumen pertukaran menunjukkan pemahaman yang mendalam.
# Exchange argument demo: earliest-finish-time activity selection
# Suppose OPT starts with activity A (not earliest-ending)
# Let G = earliest-ending activity available
# A.end >= G.end (G ends earlier or same time)
# Swap A for G in OPT:
# - G.end <= A.end, so G does not conflict with anything A allowed after it
# - OPT remains valid with the same number of activities
# - Repeat: after swap, OPT begins with G, matching greedy first choice
# By induction, OPT can be transformed to match G activity by activity
# without losing activities → greedy is optimal
print('Exchange argument: any OPT can be modified to match Greedy without loss')
print('This proves Greedy >= OPT in objective value')Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Struktur Data & Algoritma — Persiapan Wawancara Pemrograman dari pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini Anda mempelajari: pendekatan serakah benar ketika sifat pilihan serakah berlaku — hal ini dapat dibuktikan melalui argumen pertukaran, DP diperlukan ketika submasalah saling tumpang tindih (submasalah yang sama dicapai melalui beberapa cara) dan tidak dapat diselesaikan dengan satu aturan serakah, serta cara tercepat untuk membantah hipotesis serakah adalah membuat kontrapontoh dengan input yang tidak lazim. Selanjutnya, kita akan menyelesaikan Penjadwalan dan Penggabungan Interval menggunakan pendekatan serakah dengan sort berdasarkan waktu selesai.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Greedy vs DP: Kapan Menggunakan Masing-Masing” gratis?
Ya — teks lengkap “Greedy vs DP: Kapan Menggunakan Masing-Masing” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus DSA Interview Prep, upgrade ke CoddyKit PRO. Kursus DSA Interview Prep mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Greedy vs DP: Kapan Menggunakan Masing-Masing”?
Identifikasi ciri-ciri masalah yang dapat diselesaikan secara greedy dibandingkan masalah yang memerlukan DP menggunakan sifat pilihan greedy dan argumen pertukaran Kamu berlatih DSA Interview Prep dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai DSA Interview Prep?
Tidak diperlukan pengalaman sebelumnya. DSA Interview Prep di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 1 dari 4.
Berapa lama pelajaran “Greedy vs DP: Kapan Menggunakan Masing-Masing” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran DSA Interview Prep ini?
Ya. Setiap pelajaran DSA Interview Prep menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Greedy vs DP: Kapan Menggunakan Masing-Masing
- Penjadwalan dan Penggabungan Interval
- Jump Game I dan II
- Penjadwal Tugas dan Pompa Bensin