Förberedelse inför kodningsintervjuer · Lektion

Burst Balloons: omvänd intervall-DP

Lös problemet burst-balloons genom att tänka baklänges – välj vilken ballong som spricker sist i varje intervall i stället för först.

Lektion 4 av 413 steg

Burst Balloons: omvänd intervall-DP är en gratis lektion i Förberedelse inför kodningsintervjuer på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Förberedelse inför kodningsintervjuer, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Förberedelse inför kodningsintervjuer innehåller totalt 4 lektioner.

Problemet Burst Balloons

Givet n ballonger med värdena nums ger det nums[i-1] * nums[i] * nums[i+1] mynt att spräcka ballong i (produkten av dess värde och de aktuella grannarnas värden). När den spricker blir grannarna intilliggande. Hitta det maximala antalet mynt ni kan samla genom att spräcka alla ballonger. Den naiva simuleringen är svår eftersom grannarna förändras när ballonger spricker — omvänd intervall-DP kringgår elegant denna svårighet.

Varför simulering framåt misslyckas

Om vi försöker definiera dp[i][j] som det maximala antalet mynt från att spräcka ballongerna i intervallet [i, j] och funderar på vilken ballong som ska spräckas först, uppstår ett problem: att spräcka ballong k först innebär att nums[k-1] och nums[k+1] måste vara de aktuella grannarna — men de ballongerna kanske spräcks senare, vilket förändrar grannarna dynamiskt. Tillståndet är svårt att definiera på ett tydligt sätt i framåtriktningen.

Den viktiga insikten: Tänk baklänges

Tricket är att tänka på vilken ballong som spräcks sist i intervallet [i, j]. När ballong k är den sista som spräcks i [i, j] är alla andra ballonger i [i, j] redan borta. Därför är grannarna till ballong k exakt nums[i-1] och nums[j+1] — gränsballongerna precis utanför intervallet. Detta gör myntberäkningen för den sista spräckningen deterministisk: den beror inte på ordningen för tidigare spräckningar.

Definition av tillstånd och rekurrens

Lägg till sentinelballonger: lägg till och infoga 1 i början och slutet av nums för att bilda nums = [1] + nums + [1]. Definiera dp[i][j] som det maximala antalet mynt från att spräcka alla ballonger strikt mellan index i och j (exklusivt), där nums[i] och nums[j] är de kvarvarande gränsballongerna. Rekurrens: för varje möjlig sista ballong k i (i, j): dp[i][j] = max(dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]).

# With sentinels: nums = [1] + original + [1]
# dp[i][j] = max coins from bursting all balloons in open interval (i, j)
# k = last balloon to burst in (i,j)
# dp[i][j] = max over k in (i,j): dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]

Fullständig implementation

Vi fyller ut arrayen med sentinelvärden, initierar DP-tabellen till noll (tomt intervall = 0 mynt) och fyller tabellen efter stigande intervallängd. Det slutliga svaret är dp[0][n+1], vilket representerar det maximala antalet mynt från att spräcka alla ursprungliga ballonger med sentinelvärdena som permanenta gränser.

def maxCoins(nums):
    nums = [1] + nums + [1]
    n = len(nums)
    dp = [[0]*n for _ in range(n)]
    
    # length of open interval (i, j) exclusive: j - i - 1 balloons inside
    for length in range(2, n):       # length = j - i
        for i in range(0, n - length):
            j = i + length
            for k in range(i+1, j):  # k is last burst in (i, j)
                coins = dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]
                dp[i][j] = max(dp[i][j], coins)
    
    return dp[0][n-1]

print(maxCoins([3, 1, 5, 8]))  # 167

Genomgång av exemplet

För [3, 1, 5, 8], utfylld till [1, 3, 1, 5, 8, 1] (index 0–5). Vi vill ha dp[0][5]. För intervall med längden 2 (en ballong inuti): dp[0][2] = 1*3*1=3, dp[1][3]=3*1*5=15, dp[2][4]=1*5*8=40, dp[3][5]=5*8*1=40. När vi bygger upp lösningen är det optimalt att spräcka 1 sist bland {3,1,5,8}, efter att först ha spräckt grannarna, vilket ger totalt 167 mynt.

Komplexitetsanalys

Det finns O(n²) intervall, och för varje intervall provar vi O(n) delningspunkter, vilket ger O(n³) tidskomplexitet. Minnesanvändningen är O(n²) för DP-tabellen. För n = 500 ballonger innebär detta 125 miljoner operationer — genomförbart med intervjukraven. Utfyllnaden med sentinelvärden förenklar hanteringen av gränser: utan den skulle ni behöva uttryckliga kontroller av om i-1 och j+1 ligger inom gränserna.

Alternativ med memoiserad top-down-DP

Samma lösning kan skrivas top-down med @lru_cache, vilket kan vara mer intuitivt att härleda under en intervju. Definiera solve(i, j) som det maximala antalet mynt i det öppna intervallet (i, j). Funktionen provar alla k som den sista ballongen som spräcks och memoiserar resultaten. Båda metoderna har identisk tids- och minneskomplexitet.

from functools import lru_cache

def maxCoins_memo(nums):
    nums = [1] + nums + [1]
    n = len(nums)
    
    @lru_cache(maxsize=None)
    def solve(i, j):
        if j - i < 2:  # no balloons between i and j
            return 0
        return max(
            solve(i, k) + solve(k, j) + nums[i]*nums[k]*nums[j]
            for k in range(i+1, j)
        )
    
    return solve(0, n-1)

print(maxCoins_memo([3, 1, 5, 8]))  # 167

Vanligt misstag: definition av framåtriktad DP

Ett vanligt misstag är att definiera dp[i][j] som antalet mynt när den första ballongen i [i,j] spräcks, i stället för den sista. Detta misslyckas eftersom myntberäkningen för den första spräckningen beror på grannballonger som ännu inte har spräckts — och deras tillstånd förändras när algoritmen fortsätter. Tänk alltid på det sista elementet i intervall-DP när gränserna beror på de element som finns kvar.

Varför sentinelvärden på 1?

Sentinelvärden på 1 väljs eftersom de fungerar som neutrala element för multiplikation. När en gränsballong är den sista som spräcks blir dess myntvärde boundary * last * boundary = 1 * last * 1 = last. Om ni använder 0 blir resultatet 0 mynt (fel), och andra värden skulle förvränga beräkningen. Tricket med sentinelvärden förenar alla gränsfall på ett tydligt sätt utan särskild hantering av den vänstraste och högra ballongen.

Skillnad mot standardmässig intervall-DP

I standardmässig intervall-DP (matrix chain) representerar delningspunkten k var vi delar upp problemet i två delproblem som löses oberoende av varandra. I Burst Balloons är k den sista ballongen som spräcks i intervallet, vilket gör delintervallen [i,k] och [k,j] oberoende när k fortfarande finns kvar som gräns. Detta omvända perspektiv är den kreativa insikten som gör att Burst Balloons kan lösas med intervall-DP.

Snabbkontroll

Testa er förståelse av begreppen i Data Structures & Algorithms — Coding Interview Prep från den här lektionen.

Tillbakablick på lektionen

I den här lektionen har ni lärt er: framåtsimulering misslyckas eftersom när ballonger sprängs förändras grannarna på ett oförutsägbart sätt, den omvända observationen definierar k som den sista ballongen som sprängs i ett intervall, vilket gör grannarna till nums[i] och nums[j], och rekurrensen dp[i][j] = max(dp[i][k] + dp[k][j] + nums[i]*nums[k]*nums[j]) med sentinelutfyllnad ger en lösning i O(n³). Härnäst går vi över till DP för ryggsäcksproblem, med början i det klassiska 0/1-ryggsäcksproblemet och dess minnesoptimering.

Gratis att börja

Lär dig Förberedelse inför kodningsintervjuer 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
90
Lektioner
360

Vanliga frågor

Är lektionen ”Burst Balloons: omvänd intervall-DP” gratis?

Ja – hela texten till ”Burst Balloons: omvänd intervall-DP” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Förberedelse inför kodningsintervjuer, kan Ni uppgradera till CoddyKit PRO. Kursen i Förberedelse inför kodningsintervjuer innehåller totalt 4 lektioner.

Vad lär jag mig i ”Burst Balloons: omvänd intervall-DP”?

Lös problemet burst-balloons genom att tänka baklänges – välj vilken ballong som spricker sist i varje intervall i stället för först. Ni övar på Förberedelse inför kodningsintervjuer 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 Förberedelse inför kodningsintervjuer?

Du behöver inga förkunskaper. Utbildningen i Förberedelse inför kodningsintervjuer 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 4 av 4.

Hur lång tid tar lektionen ”Burst Balloons: omvänd intervall-DP”?

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 Förberedelse inför kodningsintervjuer-lektionen?

Ja. Varje Förberedelse inför kodningsintervjuer-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

  1. Mönstret för intervall-DP och fyllnadsordning
  2. Längsta palindromiska delsekvens och delsträng
  3. Palindrome Partitioning II
  4. Burst Balloons: omvänd intervall-DP
← Tillbaka till Förberedelse inför kodningsintervjuer