647、回文子串
思路一:动态规划(同5)
class Solution:
def countSubstrings(self, s: str) -> int:
l=len(s)
dp = [[False for _ in range(l)] for _ in range(l)]
res=0
for j in range(0,l):
for i in range(0,j+1):
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]:
res+=1
return res
public int countSubstrings(String s) {
int len=s.length();
boolean[][] dp=new boolean[len][len];
int res=0;
for(int j=0;j<len;j++){
for(int i=0;i<=j;i++){
if(s.charAt(i)==s.charAt(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]) res+=1;
}
}
return res;
}
}
思路二:中心拓展
- 枚举每一个可能的回文中心,然后用两个指针分别向左右两边拓展,当两个指针指向的元素相同的时候就拓展,否则停止拓展。
- 如果回文长度是奇数,那么回文中心是一个字符;如果回文长度是偶数,那么中心是两个字符。
- 共有 2 * len - 1 个中心点,中心点可以是一个字母或两个字母
aba 有5个中心点,分别是 a、b、c、ab、ba
abba 有7个中心点,分别是a、b、b、a、ab、bb、ba
class Solution:
def countSubstrings(self, s: str) -> int:
l=len(s)
res=0
for center in range(2*l-1):
left = center // 2;
right = left + center % 2;
while left>=0 and right<l and s[left]==s[right]:
left-=1
right+=1
res+=1
return res
516、最长回文子序列
注意:
【子串】和【子序列】
①上一题中,要求【字串】
for(int j=0;j<len;j++)
for(int i=0;i<=j;i++)
s[i]==s[j]
时,可以用j-i<3
规避掉dp[i][j]=dp[i+1][j-1]
中dp[i+1][j-1]
未更新;
s[i]!=s[j]
时,直接存为false即可,与之前状态无关
②本题中,要【子序列】,s[i]!=s[j]
时,还要把之前状态移过来:dp[i][j] = Math.max(dp[i + 1][j], Math.max(dp[i][j], dp[i][j - 1]));
,所以,必须从后往前遍历,
for(int i = len - 1; i >= 0; i--){
for(int j = i + 1; j < len; j++){
class Solution {
public int longestPalindromeSubseq(String s) {
int len=s.length();
int[][]dp=new int[len][len];
for(int i = len - 1; i >= 0; i--){// 从后往前遍历 保证情况不漏
dp[i][i]=1;
for(int j = i + 1; j < len; j++){
if(s.charAt(i)==s.charAt(j)){
dp[i][j] = dp[i + 1][j - 1] + 2;
}else{
dp[i][j] = Math.max(dp[i + 1][j],
Math.max(dp[i][j], dp[i][j - 1]));
}
}
}
return dp[0][len-1];
}
}