leetcode(8)回文系列题目
动态规划:
647. 回文子串
布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。
- 当s[i]与s[j]不相等,dp[i][j]一定是false。
- 当s[i]与s[j]相等时,有如下三种情况
- 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
- 情况二:下标i 与 j相差为1,例如aa,也是回文子串
- 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。
根据dp[i + 1][j - 1]是否为true,再对dp[i][j]进行赋值true的。
dp[i + 1][j - 1] 在 dp[i][j]的左下角,如图:
所以一定要从下到上,从左到右遍历,这样保证dp[i + 1][j - 1]都是经过计算的。
length = len(s)
dp = [[False] * length for _ in range(length)]
res = 0
for i in range(length - 1, -1, -1): #注意遍历顺序
for j in range(i, length):
if s[i] == s[j]:
if j - i <= 1 or dp[i + 1][j - 1] : #注意两个判断条件的顺序
res += 1
dp[i][j] = True
return res
516. 最长回文子序列
注意:与 647. 回文子串 的区别是回文子串是要连续的,回文子序列可以不连续!
-
如果s[i]与s[j]相同,那么dp[i][j] = dp[i + 1][j - 1] + 2;
-
如果s[i]与s[j]不相同,说明s[i]和s[j]的同时加入 并不能增加[i,j]区间回文子串的长度,那么分别加入s[i]、s[j]看看哪一个可以组成最长的回文子序列。
- 加入s[j]的回文子序列长度为dp[i + 1][j]。
- 加入s[i]的回文子序列长度为dp[i][j - 1]。
那么dp[i][j]一定是取最大的,即:dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
length = len(s)
dp = [[0] * length for _ in range(length)]
for i in range(length):
dp[i][i] = 1
for i in range(length - 1, -1, -1):
for j in range(i + 1, length): #注意从i+1开始遍历
if s[i] == s[j]:
dp[i][j] = dp[i + 1][j - 1] + 2
else:
dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])
return dp[0][-1]
5. 最长回文子串
注意:与 647. 回文子串 的区别是当是回文串的时候更新起始位置并记录最大长度
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
dp = [[0] * n for _ in range(n)]
left, right = 0, 0
maxL = float('-inf')
for i in range(n, -1, -1):
for j in range(i, n):
if s[i] == s[j]:
if j - i <= 1 or dp[i + 1][j - 1] == 1:
dp[i][j] = 1
if dp[i][j] == 1 and j-i+1 > maxL:
left, right = i, j
maxL = j-i+1
return s[left: left + maxL]
125. 验证回文串
双指针,里面的判断部分还可以再优化一下
class Solution:
def isPalindrome(self, s: str) -> bool:
s = s.lower()
# print(s)
left, right = 0, len(s) - 1
while left <= right:
while left < len(s) and not (s[left].isalpha() or s[left].isdigit()):
left += 1
while right >= 0 and not (s[right].isalpha() or s[right].isdigit()):
right -= 1
if left == len(s) or right == -1:
return True
if s[left] != s[right]:
return False
left += 1
right -= 1
return True