Giriga algoritmer eller DP: när används vad
Identifiera kännetecknen för problem som kan lösas girigt jämfört med problem som kräver DP, med hjälp av greedy-choice-egenskapen och bytesargumentet.
Giriga algoritmer eller DP: när används vad är en gratis lektion i DSA Interview Prep på CoddyKit. Detta är lektion 1 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för DSA Interview Prep, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i DSA Interview Prep innehåller totalt 4 lektioner.
Översikt över Greedy och DP
Både Greedy och dynamisk programmering löser optimeringsproblem – de hittar ett maximum, minimum eller en optimal sammansättning. Greedy gör det lokalt optimala valet i varje steg utan att ompröva tidigare beslut. DP utforskar alla möjligheter men använder memoisering för att undvika upprepade beräkningar. Genom att veta vilken metod som ska användas kan ni spara timmar av felsökning av en felaktig greedy-algoritm eller en onödigt komplicerad DP-tabell.
# 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')Egenskapen greedy choice
Ett problem har greedy choice property när en globalt optimal lösning alltid kan byggas genom lokalt optimala (greedy) val. Formellt finns det en optimal lösning som börjar med greedy-valet, så vi behöver aldrig backtracka. Detta bevisas vanligtvis med ett utbytesargument: anta att en godtycklig optimal lösning inte innehåller greedy-valet och visa sedan att ni kan byta in det utan att resultatet försämras.
# 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], '...')Optimal delstruktur
Både greedy och DP kräver optimal delstruktur: den optimala lösningen på hela problemet innehåller optimala lösningar på delproblem. Skillnaden är om de optimala delproblemlösningarna kan bestämmas girigt (utan att alla alternativ utforskas) eller om flera val måste jämföras. Om ni gör ett val och det återstående delproblemet har samma struktur fungerar greedy. Om ni måste jämföra flera val använder ni 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')Överlappande delproblem – tecken på DP
Om samma delproblem löses flera gånger i en rekursiv uppdelning behövs DP med memoisering. Rita upp rekursionsträdet och leta efter upprepade noder. För Fibonacci beräknas fib(3) två gånger i trädet för fib(5). För myntväxling med mynt [1,3,4] och målet 6 förekommer delproblem för målen 3, 2 och 1 flera gånger. Överlappande delproblem plus optimal delstruktur = 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)Klassiska greedy-problem
Problem där greedy är bevisat korrekt: (1) aktivitets-/intervallplanering – greedy efter tidigaste sluttid. (2) minimalt uppspännande träd – Prims och Kruskals algoritmer. (3) Huffman-kodning – slå alltid ihop de två noderna med lägst frekvens. (4) fraktionella ryggsäcksproblemet – välj objekt efter högst värde/vikt-kvot. (5) Jump Game – håll reda på det största nåbara indexet. Alla dessa kan motiveras med bevis genom utbytesargument.
# 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)När greedy misslyckas: motexempel
Att hitta ett motexempel är det snabbaste sättet att motbevisa en greedy-hypotes. För myntväxling med mynt [1, 3, 4] och målet 6 tar greedy (störst först) 4 och sedan 1+1 = 3 mynt. DP hittar 3+3 = 2 mynt. För 0/1-ryggsäcken väljer greedy efter kvot objektet med bäst kvot, men kan missa kombinationer som utnyttjar kapaciteten bättre. Om ni kan konstruera ett motexempel på under en minut bör ni byta till 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)Jämförelsetabell: Greedy jämfört med DP
Viktiga skillnader sida vid sida: tidskomplexitet – greedy är vanligtvis O(n log n) (sorteringen dominerar); DP är O(n × antal tillstånd). rymdkomplexitet – greedy använder O(1) extrautrymme; DP använder O(antal tillstånd). korrekthet – greedy kräver ett bevis; DP är alltid korrekt om tillstånden och rekurrensen är rätt. användningsområden – greedy för schemaläggning, uppspännande träd och Huffman; DP för ryggsäck, sekvensjustering och kortaste vägar med negativa vikter.
# 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')Beslutsramverk
Beslutsflödesschema för intervjuer: (1) Kan ni bevisa greedy choice property med ett utbytesargument? Ja → greedy. (2) Överlappar delproblemen (nås samma tillstånd på flera sätt)? Ja → DP. (3) Ber problemet er att räkna eller enumerera alla lösningar? → DP eller backtracking. (4) Gäller frågan ett enda optimalt värde med en naturlig ordning? Misstänk greedy. (5) När ni är osäkra, skriv DP – det är alltid korrekt om rekurrensen är rätt, även om det är långsammare.
# 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)')Intervallproblem: Greedy jämfört med DP
Intervallproblem delas mellan greedy och DP. Icke-överlappande intervall (ta bort så få som möjligt): sortera efter sluttid och välj intervall med greedy-strategin – greedy är bevisat optimalt. viktad intervallplanering (maximera den totala vikten): DP behövs eftersom tunga intervall kan överlappa många lätta och alla giltiga delmängder måste jämföras. Den avgörande faktorn är om alla intervall har samma vikt (greedy) eller varierande vikt (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]])) # 2Identifiera problemsignaler
Vanliga signaler i problemformuleringar: ”minsta antal operationer”, ”maximal vinst”, ”optimalt urval” → kan vara greedy eller DP, kontrollera överlappningar. ”räkna antalet sätt” → alltid DP. ”hitta ett giltigt schema” → kan vara greedy. ”alla möjliga” → backtracking. ”får inte välja intilliggande” → DP (house robber). ”möten, intervall, uppgifter” → sannolikt greedy. Genom att koppla signaler till algoritmfamiljer går det snabbare att diagnostisera intervjuproblem.
# 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}')Bevisa att greedy är korrekt
För att bevisa att en greedy-algoritm är korrekt använder ni utbytesargumentet: (1) Anta att det finns en optimal lösning OPT som skiljer sig från greedy-lösningen G vid det första valet. (2) Visa att ni kan byta in greedy-valet i OPT utan att objektivvärdet ökar. (3) Med induktion följer att greedy-lösningen är minst lika bra som varje optimal lösning. I intervjuer behöver ni inte ge ett fullständigt bevis, men om ni förklarar intuitionen bakom utbytesargumentet visar det djup förståelse.
# 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')Snabbtest
Testa era kunskaper om koncepten i Data Structures & Algorithms — Coding Interview Prep från den här lektionen.
Lektionssammanfattning
I den här lektionen har ni lärt er: greedy är korrekt när greedy choice property gäller – vilket kan bevisas med ett utbytesargument, DP behövs när delproblem överlappar (samma delproblem nås på flera sätt) och inte kan lösas med en enda greedy-regel, och det snabbaste sättet att motbevisa en greedy-hypotes är att konstruera ett motexempel med icke-standardiserade indata. Härnäst löser vi intervallschemaläggning och intervallsammanslagning med metoden att sortera efter sluttid.
Lär dig Python med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 30
- Lektioner
- 120
Vanliga frågor
Är lektionen ”Giriga algoritmer eller DP: när används vad” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen DSA Interview Prep, inklusive ”Giriga algoritmer eller DP: när används vad”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i DSA Interview Prep innehåller totalt 4 lektioner.
Vad lär jag mig i ”Giriga algoritmer eller DP: när används vad”?
Identifiera kännetecknen för problem som kan lösas girigt jämfört med problem som kräver DP, med hjälp av greedy-choice-egenskapen och bytesargumentet. Ni övar på DSA Interview Prep med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig DSA Interview Prep?
Du behöver inga förkunskaper. Utbildningen i DSA Interview Prep på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.
Hur lång tid tar lektionen ”Giriga algoritmer eller DP: när används vad”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här DSA Interview Prep-lektionen?
Ja. Varje DSA Interview Prep-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Giriga algoritmer eller DP: när används vad
- Intervallschemaläggning och sammanslagning
- Jump Game I och II
- Task Scheduler och Gas Station