647. 回文子串
题目链接:https://leetcode.com/problems/palindromic-substrings
解法:
这道题代码量不大,但是要每一步都需要认真考虑。
1. 定义dp[i][j]的含义
dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是,则dp[i][j]为true,否则为false。
这里dp不再直接对应问题:dp[i] 为 下标i结尾的字符串有 dp[i]个回文串。这样找不到递推关系。
2. 递推关系
如果s[i] = s[j] 且 j - i <= 2,比如:a,aa,aba,那么都是回文子串。如果j - j > 2,那么如果s[i+1:j-1] 闭区间是回文子串,那么s[i:j]闭区间也是。
所以条件是 if s[i] == s[j] and (j -i i <= 2 or dp[i+1][j-1]),则dp[i][j] = True
3. 遍历顺序
由于需要提前得到dp[i+1][j-1],那么i的遍历是从右到左。
也可以用双指针降低空间复杂度。
首先确定回文串,就是找中心然后向两边扩散看是不是对称的就可以了。
在遍历中心点的时候,要注意中心点有两种情况。
一个元素可以作为中心点,两个元素也可以作为中心点。
边界条件:无
时间复杂度:动态规划O(n^2), 双指针O(n^2)
空间复杂度:动态规划O(n^2), 双指针O(1)
class Solution(object):
def countSubstrings(self, s):
dp = [[False] * len(s) for _ in s]
result = 0
for i in range(len(s), -1, -1):
for j in range(i, len(s)):
if s[i] == s[j] and (j-i<=2 or dp[i+1][j-1]):
result += 1
dp[i][j] = True
return result
# 双指针版本
class Solution(object):
def countSubstrings(self, s):
result = 0
for i in range(len(s)):
result += self.extend(s, i, i)
result += self.extend(s, i, i+1)
return result
def extend(self, s, i, j):
result = 0
while i >= 0 and j < len(s) and s[i] == s[j]:
i -= 1
j += 1
result += 1
return result
516.最长回文子序列
题目链接:https://leetcode.com/problems/longest-palindromic-subsequence/
解法:
1. 确定dp数组(dp table)以及下标的含义
dp[i][j]:字符串s在[i, j]范围内最长的回文子序列的长度为dp[i][j]。
2. 确定递推公式
在判断回文子串的题目中,关键逻辑就是看s[i]与s[j]是否相同。
如果s[i]与s[j]相同,那么dp[i][j] = dp[i + 1][j - 1] + 2.
如果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])。
3. 初始化
dp[i][i] = 1,其他为0,比如dp[3][2],由于s[3:2]是不可能取到了,也初始化为0。
其他需要注意的点就是对j的遍历是从i+1开始,而不是i+2,尽管dp[i+1][j-1]在i+1时,截取字符串是不行的。
最后是返回dp[0][-1],因为这表示整条字符串。
边界条件:无
时间复杂度:O(n^2)
空间复杂度:O(n^2)
class Solution(object):
def longestPalindromeSubseq(self, s):
dp = [[0] * len(s) for _ in s]
for i in range(len(s)):
dp[i][i] = 1
for i in range(len(s)-1, -1, -1):
for j in range(i+1, len(s)):
# s[i] = s[j] 的情况,如果 s[3][2]是不行的,
# 所以dp[3][2]初始化为0了,于是下边也可运行
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] + 2
else:
dp[i][j] = max(dp[i+1][j], dp[i][j-1])
return dp[0][-1]