DSA Interview Prep · Lektion

Længste palindromiske delsekvens og delstreng

Anvend interval-DP til at finde den længste palindromiske delsekvens og tricket med at udvide omkring centrum til at finde den længste palindromiske delstreng.

Lektion 2 af 413 trin

Længste palindromiske delsekvens og delstreng er en gratis DSA Interview Prep-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i DSA Interview Prep, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. DSA Interview Prep-kurset indeholder 4 lektioner i alt.

Palindromdefinitioner — en gentagelse

En palindromisk delsekvens er en delsekvens (elementerne behøver ikke at være sammenhængende), der læses ens forfra og bagfra. En palindromisk delstreng kræver sammenhængende tegn. For 'bbbab' er den længste palindromiske delsekvens 'bbbb' (længde 4), mens den længste palindromiske delstreng er 'bbb' (længde 3). De to problemer kræver forskellige teknikker trods deres lignende navne.

Længste palindromiske delsekvens: LPS-tilstanden

Definér dp[i][j] som længden af den længste palindromiske delsekvens i s[i..j]. Rekurrensformlen er: Hvis s[i] == s[j], så er dp[i][j] = dp[i+1][j-1] + 2 (de to ens tegn udvider det indre palindrom). Ellers er dp[i][j] = max(dp[i+1][j], dp[i][j-1]) (spring det venstre eller højre tegn over). Basistilfælde: dp[i][i] = 1 for alle enkelte tegn.

s = 'bbbab'
n = len(s)
dp = [[0]*n for _ in range(n)]
for i in range(n):
    dp[i][i] = 1
print('Base cases set, dp[i][i] = 1 for all i')

LPS-udfyldningsrækkefølge og implementering

Vi udfylder LPS-tabellen i stigende intervallængde, efter samme mønster som generel interval-DP. For hvert interval [i, j] med længde 2 eller mere kontrollerer vi, om de to grænsetegn er ens, og anvender rekurrensformlen. Det endelige svar er dp[0][n-1], LPS for hele strengen.

def longest_palindromic_subsequence(s):
    n = len(s)
    dp = [[0]*n for _ in range(n)]
    for i in range(n):
        dp[i][i] = 1
    
    for length in range(2, n+1):
        for i in range(n - length + 1):
            j = i + length - 1
            if s[i] == s[j]:
                inner = dp[i+1][j-1] if length > 2 else 0
                dp[i][j] = inner + 2
            else:
                dp[i][j] = max(dp[i+1][j], dp[i][j-1])
    return dp[0][n-1]

print(longest_palindromic_subsequence('bbbab'))  # 4

LPS via ækvivalens med LCS

Et elegant alternativ: LPS for strengen s er lig med LCS for s og dens omvendte streng s[::-1]. Det skyldes, at enhver palindromisk delsekvens i s er en fælles delsekvens for s og dens omvendte streng. Denne omskrivning giver dig mulighed for at genbruge din LCS-implementering direkte. Den omvendte version af 'bbbab' er 'babbb', og deres LCS er 4.

def lps_via_lcs(s):
    t = s[::-1]
    m, n = len(s), len(t)
    dp = [[0]*(n+1) for _ in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s[i-1] == t[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]

print(lps_via_lcs('bbbab'))  # 4

Længste palindromiske delstreng: brute force

Den længste palindromiske delstreng kræver sammenhængende tegn. En brute force-tilgang kontrollerer alle O(n²) delstrenge og verificerer hver af dem i O(n)-tid — O(n³) i alt. Der findes to hurtigere tilgange: interval-DP i O(n²)-tid og med O(n²)-pladsforbrug samt udvidelse omkring centrum i O(n²)-tid, men med O(1)-pladsforbrug. Til interviews foretrækkes udvidelse omkring centrum, fordi den har en mindre konstant faktor og renere kode.

Interval-DP for palindromiske delstrenge

Definér dp[i][j] = True, hvis s[i..j] er et palindrom. Rekurrensformel: dp[i][j] = (s[i] == s[j]) and dp[i+1][j-1]. Basistilfælde: dp[i][i] = True og dp[i][i+1] = (s[i] == s[i+1]). Hold styr på det længste fundne palindrom. Udfyld tabellen i stigende længderækkefølge. Det kører i O(n²)-tid og bruger O(n²)-plads.

def longest_palindrome_dp(s):
    n = len(s)
    dp = [[False]*n for _ in range(n)]
    start, max_len = 0, 1
    for i in range(n):
        dp[i][i] = True
    for i in range(n-1):
        if s[i] == s[i+1]:
            dp[i][i+1] = True
            start, max_len = i, 2
    for length in range(3, n+1):
        for i in range(n - length + 1):
            j = i + length - 1
            if s[i] == s[j] and dp[i+1][j-1]:
                dp[i][j] = True
                if length > max_len:
                    start, max_len = i, length
    return s[start:start+max_len]

print(longest_palindrome_dp('babad'))  # 'bab' or 'aba'

Teknikken udvidelse omkring centrum

Tilgangen med udvidelse omkring centrum prøver hvert tegn (samt hvert par af tilstødende tegn) som et muligt palindromcentrum og udvider udad, så længe begge sider matcher. Der er 2n-1 mulige centre (n for ulige længder og n-1 for lige længder). Hver udvidelse tager højst O(n)-tid, hvilket giver O(n²) i alt med O(1)-pladsforbrug — optimalt i de fleste interviewsituationer.

def longest_palindrome_expand(s):
    def expand(l, r):
        while l >= 0 and r < len(s) and s[l] == s[r]:
            l -= 1
            r += 1
        return r - l - 1  # length of palindrome
    
    start, max_len = 0, 1
    for i in range(len(s)):
        odd = expand(i, i)      # odd-length
        even = expand(i, i+1)   # even-length
        best = max(odd, even)
        if best > max_len:
            max_len = best
            start = i - (best - 1) // 2
    return s[start:start+max_len]

print(longest_palindrome_expand('cbbd'))  # 'bb'

Pladsoptimering af LPS

Interval-DP for LPS bruger O(n²)-plads. Når du kun har brug for længden (og ikke den faktiske delsekvens), kan du reducere pladsforbruget ved at bemærke, at dp[i][j] kun afhænger af dp[i+1][j-1], dp[i+1][j] og dp[i][j-1]. Ved at genbruge rækker og gemme én diagonalværdi kan du opnå O(n)-plads — implementeringen bliver dog mere kompleks, og det er sjældent nødvendigt i interviews.

Genskabelse af LPS

Hvis du vil genskabe den faktiske palindromiske delsekvens, skal du spore tilbage gennem DP-tabellen. Start ved (0, n-1). Hvis s[i] == s[j], skal du føje tegnet til begge ender af dit resultat og gå til (i+1, j-1). Ellers skal du gå til den af (i+1, j) og (i, j-1), der har den største værdi. Denne grådige tilbagesporing genskaber entydigt én optimal palindromisk delsekvens.

def reconstruct_lps(s, dp):
    result = []
    i, j = 0, len(s) - 1
    while i < j:
        if s[i] == s[j]:
            result.append(s[i])
            i += 1; j -= 1
        elif dp[i+1][j] > dp[i][j-1]:
            i += 1
        else:
            j -= 1
    # middle character for odd-length
    mid = [s[i]] if i == j else []
    return ''.join(result + mid + result[::-1])

print('Traceback recovers one optimal LPS')

Sammenligning af tidsforbruget for LPS og LCS

Både LPS via interval-DP og LCS kører i O(n²)-tid og bruger O(n²)-plads. Udvidelse omkring centrum for den længste palindromiske delstreng bruger O(n²)-tid, men kun O(1)-plads. Manachers algoritme løser delstrengsproblemet i O(n)-tid og med O(n)-plads, men den er så kompleks, at interviewere sjældent forventer den. I de fleste interviewsituationer er udvidelse omkring centrum den forventede optimale løsning på delstrengsvarianten.

Almindelige faldgruber og kanttilfælde

Vær opmærksom på disse faldgruber: (1) at forveksle subsekvens med delstreng — det er forskellige problemer med forskellige løsninger; (2) basistilfældet i interval-DP'en for intervaller af længde 2 kræver særskilt håndtering, eftersom dp[i+1][j-1] ville være dp[i+1][i] (et tomt interval); (3) ved udvidelse omkring centrum skal du initialisere max_len = 1 (hvert enkelt tegn er et palindrom); og (4) når du udtrækker resultatet, skal du beregne start = i - (best-1)//2 for korrekt at finde startindekset ud fra centrum.

Hurtigt tjek

Test din forståelse af begreberne Data Structures & Algorithms — Coding Interview Prep fra denne lektion.

Opsummering af lektionen

I denne lektion lærte du: LPS bruger interval-DP med rekurrensen dp[i][j] = dp[i+1][j-1]+2, når tegnene matcher, den længste palindromiske delstreng løses bedst med udvidelse omkring centrum i O(n²)-tid og med O(1)-pladsforbrug, og LPS er lig med LCS for strengen og dens omvendte streng. Næste emne er palindromopdeling II, hvor en palindromtabel kombineres med 1D-DP for at finde det mindste antal snit.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
30
Lektioner
120

Ofte stillede spørgsmål

Er lektionen “Længste palindromiske delsekvens og delstreng” gratis?

Ja — alle 3 lektioner i læringssporet DSA Interview Prep, inklusive “Længste palindromiske delsekvens og delstreng”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. DSA Interview Prep-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Længste palindromiske delsekvens og delstreng”?

Anvend interval-DP til at finde den længste palindromiske delsekvens og tricket med at udvide omkring centrum til at finde den længste palindromiske delstreng. Du øver dig i DSA Interview Prep med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på DSA Interview Prep?

Der kræves ingen tidligere erfaring. DSA Interview Prep på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “Længste palindromiske delsekvens og delstreng”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne DSA Interview Prep-lektion?

Ja. Alle DSA Interview Prep-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Interval-DP-mønster og udfyldningsrækkefølge
  2. Længste palindromiske delsekvens og delstreng
  3. Palindrome Partitioning II
  4. Burst Balloons: Omvendt interval-DP
← Tilbage til DSA Interview Prep