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.
Længste palindromiske delsekvens og delstreng er en gratis Forberedelse til kodeinterviews-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Forberedelse til kodeinterviews, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Forberedelse til kodeinterviews-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')) # 4LPS 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')) # 4Læ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.
Lær Forberedelse til kodeinterviews 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
- 90
- Lektioner
- 360
Ofte stillede spørgsmål
Er lektionen “Længste palindromiske delsekvens og delstreng” gratis?
Ja — hele teksten til “Længste palindromiske delsekvens og delstreng” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Forberedelse til kodeinterviews-kurset, skal du opgradere til CoddyKit PRO. Forberedelse til kodeinterviews-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 Forberedelse til kodeinterviews 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å Forberedelse til kodeinterviews?
Der kræves ingen tidligere erfaring. Forberedelse til kodeinterviews 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 Forberedelse til kodeinterviews-lektion?
Ja. Alle Forberedelse til kodeinterviews-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
- Interval-DP-mønster og udfyldningsrækkefølge
- Længste palindromiske delsekvens og delstreng
- Palindrome Partitioning II
- Burst Balloons: Omvendt interval-DP