題目描述
解題思路
迴文數:迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。(第1個數和第n個數相等,第2個數和第n-1個數相等…)
解法一:暴力法(超時)
python代碼
- 枚舉所有長度大於等於 2的子串,依次判斷它們是否是迴文;
- ‘babad’,判斷‘ba’,‘bab’,‘baba’,‘babad’,‘ab’,‘aba’,‘abad’,‘ba’,‘bad’,‘ad’是否符合迴文數
- 找到最長的迴文子串,例如‘ccc’,最長迴文子串爲‘ccc’,則需加上判斷j-i+1>max_len
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n<2:
return s
res = s[0]
max_len = 1
for i in range(0,n-1):
for j in range(i+1,n):
if j-i+1>max_len and self.valid(s,i,j):
max_len = j-i+1
res = s[i:j+1]
return res
def valid(self,s,m,n):
while m<n:
if s[m] != s[n]:
return False
else:
m += 1
n -=1
return True
複雜度分析:
時間複雜度:O(n^3),這裏n是字符串的長度,枚舉字符串的左邊界、右邊界,然後繼續驗證子串是否是迴文子串,這三種操作都與n相關
空間複雜度:O(1),只使用到常數個臨時變量
解法二:動態規劃
1、如果一個字符串的頭尾兩個字符都不相等,那麼這個字符串一定不是迴文串;
2、如果一個字符串的頭尾兩個字符相等,纔有必要繼續判斷下去。
(1)如果裏面的子串是迴文,整體就是迴文串;
(2)如果裏面的子串不是迴文串,整體就不是迴文串。
瞭解動態規劃:
1、思考狀態
dp[i][j] 表示子串 s[i, j] 是否爲迴文子串。
2、思考狀態轉移方程(核心、難點)
這一步在做分類討論(根據頭尾字符是否相等),根據上面的分析得到:
dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
分析這個狀態轉移方程:
(1)“動態規劃”事實上是在填一張二維表格,i 和 j 的關係是 i <= j ,因此,只需要填這張表的上半部分;
(2)看到 dp[i + 1][j - 1] 就得考慮邊界情況。
邊界條件是:表達式 [i + 1, j - 1] 不構成區間,即長度嚴格小於 2,即 j - 1 - (i + 1) + 1 < 2 ,整理得 j - i < 3。
這個結論很顯然:當子串 s[i, j] 的長度等於 2 或者等於 3 的時候,我其實只需要判斷一下頭尾兩個字符是否相等就可以直接下結論了。
如果子串 s[i + 1, j - 1] 只有 1 個字符,即去掉兩頭,剩下中間部分只有1個字符,當然是迴文;
如果子串 s[i + 1, j - 1] 爲空串,那麼子串 s[i, j] 一定是迴文子串。
因此,在 s[i] == s[j] 成立和 j - i < 3 的前提下,直接可以下結論,dp[i][j] = true,否則才執行狀態轉移。
3、思考初始化
初始化的時候,單個字符一定是迴文串,因此把對角線先初始化爲 1,即 dp[i][i] = 1
4、思考輸出
只要一得到 dp[i][j] = true,就記錄子串的長度和起始位置,沒有必要截取,因爲截取字符串也要消耗性能,記錄此時的迴文子串的“起始位置”和“迴文長度”即可。
5、思考狀態壓縮
因爲在填表的過程中,只參考了左下方的數值。事實上可以壓縮,但會增加一些判斷語句,增加代碼編寫和理解的難度,丟失可讀性。在這裏不做狀態壓縮。
python代碼
class Solution:
def longestPalindrome(self, s: str) -> str:
size = len(s)
if size < 2:
return s
dp = [[False for _ in range(size)] for _ in range(size)]
max_len = 1
start = 0
for i in range(size):
dp[i][i] = True
for j in range(1, size):
for i in range(0, j):
if s[i] == s[j]:
if j - i < 3:
dp[i][j] = True
else:
dp[i][j] = dp[i + 1][j - 1]
else:
dp[i][j] = False
if dp[i][j]:
cur_len = j - i + 1
if cur_len > max_len:
max_len = cur_len
start = i
return s[start:start + max_len]
複雜度分析:
時間複雜度:O(n^2)
空間複雜度:O(n^2)二維 dp 問題,一個狀態得用二維有序數對錶示,因此空間複雜度是 O(n^2)