0Pricing
Coding Interview Prep · Ders

Madeni Para Değişimi ve Minimum Maliyetli Merdiven

Madeni para değişimi ve minimum maliyetli merdiven tırmanma bağıntılarını kurun, doğru DP yönünü seçin ve tabloyu elle adım adım izleyin.

Madeni Para Değişimi ve Minimum Maliyetli Merdiven, CoddyKit'te ücretsiz bir Coding 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, Coding Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Coding Interview Prep kursu toplamda 4 dersten oluşur.

Madeni Para Değişimi: Problem

Madeni Para Değişimi (LeetCode #322) size madeni para kupürleri ve bir hedef miktar verir. Tam olarak bu miktarı oluşturmak için gereken en az madeni para sayısını bulun. Her kupürden sınırsız sayıda madeni paranız vardır. Bu, klasik bir sınırsız sırt çantası çeşididir — her öğe (madeni para) istenen sayıda kullanılabilir. Sıfırdan bir bağıntı kurma becerinizi sınadığı için en önemli DP problemlerinden biridir.

# Problem examples:
# coins=[1,5,6,9], amount=11 -> 2 (5+6 or 2+9? no: 5+6=11 YES)
# coins=[2],       amount=3  -> -1 (impossible)
# coins=[1,2,5],   amount=11 -> 3 (5+5+1)
# coins=[186,419,83,408], amount=6249 -> 20

# Key choices:
# - Try each coin denomination at each step
# - Minimum coins = 1 + minimum(coins to make amount - coin)
# - If amount < 0: impossible
# - If amount = 0: done (0 coins)

print('Coin change: unbounded knapsack, find minimum count')

Madeni Para Değişimi: Bağıntının Türetilmesi

dp[i] = i miktarını oluşturmak için gereken en az madeni para sayısı olacak şekilde tanımlayın. Her miktar i için her madeni para c'yi kullanmayı deneyin: i >= c ise dp[i] = min(dp[i], 1 + dp[i-c]) olur. Buradaki '1', az önce kullandığımız madeni parayı temsil eder; dp[i-c] ise geriye kalan miktar için en iyi çözümdür. Bu, sınırsız sayıda madeni para bulunduğunu varsayar. Temel durum: dp[0] = 0. 'Henüz ulaşılabilir değil' durumunu göstermek için diğer tüm girişleri sonsuz olarak başlatın.

def coin_change(coins, amount):
    # dp[i] = min coins to make amount i
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0  # base: 0 coins for amount 0

    for i in range(1, amount + 1):
        for coin in coins:
            if i >= coin and dp[i - coin] != float('inf'):
                dp[i] = min(dp[i], 1 + dp[i - coin])

    return dp[amount] if dp[amount] != float('inf') else -1

print(coin_change([1, 5, 6, 9], 11))  # 2
print(coin_change([2], 3))             # -1
print(coin_change([1, 2, 5], 11))      # 3

# Trace dp for coins=[1,5] amount=6:
# dp[0]=0, dp[1]=1, dp[2]=2, dp[3]=3, dp[4]=4, dp[5]=1, dp[6]=2

Açgözlü Yaklaşım Neden Başarısız Olur

Açgözlü yaklaşım (sığan en büyük madeni parayı her zaman seçmek) madeni para değişiminde başarısız olur. Örnek: coins=[1, 3, 4], amount=6. Açgözlü yaklaşım önce 4'ü, ardından 1+1'i seçerek 3 madeni para kullanır. En iyi çözüm ise 3+3 = 2 madeni paradır. Açgözlü yaklaşım, standart kupürlerde (1, 5, 10, 25 sent) işe yarar; çünkü bu kupürler tesadüfen açgözlü yaklaşım özelliğini karşılar. Ancak keyfi madeni para kümelerinde DP gerekir. Bu, mülakatlarda sık karşılaşılan bir noktadır — açgözlü yaklaşımın başarısız olduğunu belirtmek ve nedenini açıklamak, güçlü bir analitik düşünme becerisi gösterir.

# Greedy failure example:
# coins=[1,3,4], amount=6
# Greedy: 4 (rem=2), 1 (rem=1), 1 (rem=0) -> 3 coins
# Optimal: 3 (rem=3), 3 (rem=0) -> 2 coins

def coin_change_greedy_wrong(coins, amount):
    coins_sorted = sorted(coins, reverse=True)
    count = 0
    for coin in coins_sorted:
        while amount >= coin:
            amount -= coin
            count += 1
    return count if amount == 0 else -1

print('Greedy:', coin_change_greedy_wrong([1,3,4], 6))  # 3 (WRONG)
print('DP:    ', coin_change([1,3,4], 6))               # 2 (CORRECT)

Madeni Para Değişimi II: Yolları Sayma

Madeni Para Değişimi II (LeetCode #518), miktarı oluşturmanın kaç farklı yolu olduğunu sorar (en az madeni para sayısını değil). Bağıntı değişir: min yerine toplam kullanılır. Her madeni para için dp[i] += dp[i-coin] uygulanır. Doldurma sırası önemlidir: Her kombinasyonu bir kez saymak için dış döngüde madeni paraları, iç döngüde miktarları dolaşın. Döngülerin yerini değiştirmek kombinasyonlar yerine permütasyonları sayar (farklı bir problem).

def coin_change_ii(coins, amount):
    # dp[i] = number of ways to make amount i
    dp = [0] * (amount + 1)
    dp[0] = 1  # one way to make amount 0: use no coins

    # Outer loop: coins -- ensures each coin type processed once
    for coin in coins:
        # Inner loop: amounts
        for i in range(coin, amount + 1):
            dp[i] += dp[i - coin]

    return dp[amount]

print(coin_change_ii([1, 2, 5], 5))   # 4: [1,1,1,1,1],[1,1,1,2],[1,2,2],[5]
print(coin_change_ii([2], 3))          # 0: impossible
print(coin_change_ii([10], 10))        # 1

# Key: coin outer, amount inner = COMBINATIONS (unordered)
# Reverse (amount outer, coin inner) = PERMUTATIONS (ordered)

Minimum Maliyetli Merdiven: Problem

Minimum Maliyetle Merdiven Çıkma (LeetCode #746), her basamağın bir maliyeti olduğu bir merdiven verir. Her seferinde 1 veya 2 basamak çıkabilirsiniz. Tepeye (son basamağın bir ötesine) ulaşmanın minimum maliyetini bulun. 0. veya 1. basamaktan ücretsiz başlayabilirsiniz. Bu problem, merdiven çıkma bağıntısını madeni para değişimindeki maliyet en aza indirme örüntüsüyle zarif bir şekilde birleştirir ve ikisi arasında doğal bir köprü kurar.

# cost = [10, 15, 20]
# Pay cost[i] to leave step i
# You can step to i+1 or i+2
# Goal: reach top (index 3) with minimum cost

# Path options:
# Start at 0: cost 10, go to 2: cost 20, done -> 30
# Start at 1: cost 15, go to 3: done -> 15  <- OPTIMAL
# Start at 0: cost 10, go to 1: cost 15 -> 25

cost = [10, 15, 20]
# Optimal: start at step 1, pay 15, jump to top -> cost = 15
print('Expected:', 15)

Minimum Maliyetli Merdiven: Bağıntı

dp[i] = i. basamağa ulaşmanın minimum maliyeti olacak şekilde tanımlayın. i. basamağa, i-1. basamaktan cost[i-1] maliyetini ödeyerek veya i-2. basamaktan cost[i-2] maliyetini ödeyerek ulaşırsınız. Bu nedenle dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2]) olur. Temel durumlar: dp[0] = 0 (merdivenlerin öncesinden başlamak ücretsizdir), dp[1] = 0 (1. basamaktan da ücretsiz başlanabilir). Yanıt, n = len(cost) için dp[n] değeridir.

def min_cost_climbing_stairs(cost):
    n = len(cost)
    # dp[i] = minimum cost to reach step i
    # Steps 0 to n; step n is the top (goal)
    dp = [0] * (n + 1)
    # dp[0] = 0 (free to start here)
    # dp[1] = 0 (free to start here)
    for i in range(2, n + 1):
        dp[i] = min(dp[i-1] + cost[i-1],   # step from i-1
                    dp[i-2] + cost[i-2])    # jump from i-2
    return dp[n]

print(min_cost_climbing_stairs([10, 15, 20]))      # 15
print(min_cost_climbing_stairs([1,100,1,1,1,100,1,1,100,1]))  # 6

Minimum Maliyetli Merdiven: Bellek Kullanımını O(1)'e İndirme

dp[i] yalnızca dp[i-1] ve dp[i-2]'ye bağlı olduğundan, tıpkı Fibonacci'de olduğu gibi iki değişkenle alanı O(1)'e düşürebiliriz. Diziyi prev2 ve prev1 ile değiştirin. Her adımda bu değişkenleri güncelleyin. Bu, O(n) tablo çözümünü sunduktan sonra mülakat yapanların beklediği standart tek satırlık optimizasyondur. Bunu her zaman proaktif olarak belirtin: 'Yalnızca son iki değere ihtiyaç duyduğumuz için bunu O(1) belleğe düşürebiliriz.'

def min_cost_optimised(cost):
    n = len(cost)
    prev2, prev1 = 0, 0  # dp[0] and dp[1]
    for i in range(2, n + 1):
        curr = min(prev1 + cost[i-1], prev2 + cost[i-2])
        prev2, prev1 = prev1, curr
    return prev1

print(min_cost_optimised([10, 15, 20]))  # 15
print(min_cost_optimised([1,100,1,1,1,100,1,1,100,1]))  # 6

# Alternative: directly use cost array as rolling storage
def min_cost_v2(cost):
    n = len(cost)
    for i in range(2, n):
        cost[i] += min(cost[i-1], cost[i-2])
    return min(cost[-1], cost[-2])

from copy import deepcopy
cost_test = [10,15,20]
print(min_cost_v2(deepcopy(cost_test)))  # 15

Alternatif DP Formülasyonu

Bazı problemlerin birden fazla geçerli DP formülasyonu vardır. Minimum maliyetli merdiven için dp[i] = i. basamaktan LEAVE etmenin minimum maliyeti olacak şekilde tanımlama yapabilirsiniz (cost[i]'yi ödeyip i+1 veya i+2'ye gitmeyi seçersiniz). Bu durumda dp[i] = cost[i] + min(dp[i+1], dp[i+2]) bağıntısını sağdan sola doldurursunuz ve yanıt min(dp[0], dp[1]) olur. Her iki formülasyon da doğrudur. Hangi formülasyonu seçtiğinizi ve nedenini açıklama pratiği yapın — bu, DP konusundaki yetkinliğinizi gösterir.

def min_cost_alternative(cost):
    n = len(cost)
    # dp[i] = min cost when starting FROM step i
    # Fill right to left
    dp = cost[:] + [0]  # dp[n] = 0 (already at top)
    for i in range(n - 1, -1, -1):
        # Pay cost[i], then choose i+1 or i+2
        if i + 2 <= n:
            dp[i] = cost[i] + min(dp[i+1], dp[i+2])
        else:
            dp[i] = cost[i] + dp[i+1]
    # Can start at step 0 or step 1
    return min(dp[0], dp[1])

print(min_cost_alternative([10, 15, 20]))  # 15
print(min_cost_alternative([1,100,1,1,1,100,1,1,100,1]))  # 6

Madeni Para Değişimi ile Merdiven Çıkmayı İlişkilendirme

Hem madeni para değişimi hem de minimum maliyetli merdiven, aynı DP örüntüsünün örnekleridir: Her adımda sonlu bir seçenekler kümesinden bir seçim yapar ve seçimler dizisi üzerindeki bir amacı en iyi duruma getirmeye çalışırsınız. Farklar yüzeyseldir: madeni para değişimi sayıyı izler (her madeni para için 1 ekler), merdiven ise maliyeti izler (her basamak için cost[i] ekler). Bu ortak yapıyı tanımak, yeni DP problemlerini tanıdık şablonlarla eşleştirerek çözmenizi sağlar.

# Shared pattern:
# dp[state] = optimise(dp[prev_state_1] + cost_1,
#                      dp[prev_state_2] + cost_2, ...)

# Coin change:  dp[amount] = min(1 + dp[amount - coin] for coin in coins)
# Min stair:    dp[step]   = min(cost[step-1]+dp[step-1], cost[step-2]+dp[step-2])
# Max path sum: dp[cell]   = max(dp[top], dp[left]) + grid[cell]
# House robber: dp[house]  = max(dp[house-1], dp[house-2] + value[house])

# All four are the SAME pattern with different:
# - State representation
# - Number of choices per state
# - Objective (min/max)
# - Transition cost
print('DP pattern: state + choices + objective + cost = template')

Minimum Tam Kare Sayısı

Tam Kareler (LeetCode #279), toplamları n olan tam karelerin (1, 4, 9, 16, ...) minimum sayısını bulmanızı ister. Bu, 'madeni paraların' tam kare sayılar olduğu bir madeni para değişimi problemidir. n'e kadar olan tüm tam kareleri üretin, ardından madeni para değişimi çözümünü çalıştırın. DP, O(n * sqrt(n)) time gerektirir. Lagrange'ın Dört Kare Teoremi, yanıtın en fazla 4 olduğunu söyler; bu da O(sqrt(n)) zamanında matematiksel bir yaklaşım sağlar — ancak beklenen çözüm DP'dir.

import math

def num_squares(n):
    # Generate all perfect squares up to n
    squares = [i*i for i in range(1, int(math.sqrt(n)) + 1)]
    # Coin change with squares as 'coins'
    dp = [float('inf')] * (n + 1)
    dp[0] = 0
    for i in range(1, n + 1):
        for sq in squares:
            if i >= sq:
                dp[i] = min(dp[i], 1 + dp[i - sq])
    return dp[n]

print(num_squares(12))  # 3: 4+4+4
print(num_squares(13))  # 2: 4+9
print(num_squares(1))   # 1: 1

DP'de Hata Ayıklama: Yaygın Hatalar

Yaygın DP hataları şunlardır: yanlış temel durum (dp[0]'ın yanlış ayarlanması), yanlış doldurma sırası (henüz hesaplanmamış bir değere erişilmesi), durum tanımında bir eksik veya fazla (dp[i]'nin i. basamağa ULAŞMA maliyeti ile i. basamaktan AYRILMA maliyeti arasındaki farkın karıştırılması) ve sonsuz kaldığında -1 döndürmeme (imkânsız durumlar). Daha büyük girdileri sınamadan önce her zaman en basit durumlarda (boş girdi, tek öğe, hedef=0) çözümünüzü sınayın.

# Common DP debugging checklist:
# 1. Base case: what is dp[0]? dp[1]? Are they correct?
# 2. State definition: write it in English before coding
# 3. Recurrence: trace manually on a 3-element example
# 4. Fill order: dependency arrows point left/up? Fill left/up first
# 5. Infinity check: return -1 or 0 when dp[target] == inf?
# 6. Array bounds: dp has size n+1 for 0..n, or n for 0..n-1?

# Quick test template:
def test_coin_change():
    assert coin_change([1], 0) == 0     # base case
    assert coin_change([1], 1) == 1     # single coin
    assert coin_change([2], 3) == -1    # impossible
    assert coin_change([1,5,6,9], 11) == 2
    print('All tests passed!')

test_coin_change()

Hızlı Kontrol

Bu dersteki Veri Yapıları ve Algoritmalar — Kodlama Mülakatı Hazırlığı kavramlarını anlayıp anlamadığınızı sınayın.

Ders Özeti

Bu derste şunları öğrendiniz: madeni para değişiminde minimum sayı DP'si (sınırsız sırt çantası) ve açgözlü yaklaşımın neden başarısız olduğu, madeni paraların dışta ve miktarların içte dolaşıldığı sırayla kombinasyonları saymak için madeni para değişimi II ve hem soldan sağa hem de sağdan sola formülasyonlarıyla minimum maliyetli merdiven. Sırada ev soyguncusu, Kadane algoritması ve sözcük bölme ile 1B DP örüntülerini inceleyeceğiz.

Sıkça Sorulan Sorular

“Madeni Para Değişimi ve Minimum Maliyetli Merdiven” dersi ücretsiz mi?

Evet — “Madeni Para Değişimi ve Minimum Maliyetli Merdiven” 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 Coding Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Coding Interview Prep kursu toplamda 4 dersten oluşur.

“Madeni Para Değişimi ve Minimum Maliyetli Merdiven” dersinde ne öğreneceğim?

Madeni para değişimi ve minimum maliyetli merdiven tırmanma bağıntılarını kurun, doğru DP yönünü seçin ve tabloyu elle adım adım izleyin. Coding 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.

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

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

“Madeni Para Değişimi ve Minimum Maliyetli Merdiven” 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 Coding Interview Prep dersinde kod yazıp çalıştırabilir miyim?

Evet. Her Coding 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. DP’yi Tanıma: Çakışan Alt Problemler
  2. Not Almayla Yukarıdan Aşağı DP
  3. Tablolamayla Aşağıdan Yukarı DP
  4. Madeni Para Değişimi ve Minimum Maliyetli Merdiven
← Coding Interview Prep Sayfasına Dön