给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:"abc"
输出:3
解释:三个回文子串: "a", "b", "c"
示例 2:
输入:"aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
法1:中心拓展法
遍历每一个可能的回文子串的中心,从中心同时向两边拓展,两边相等个数加一,两边不相等跳过这个中心。
可能的中心个数:
单中心:n,双中心:n-1
一共2n-1
每个中心的左右起始位置:
单中心:left=right=i(i取值从0到n-1)
双中心:left=i,right=i+1(i取值从0到n-2)
于是:left = center / 2,right = left + center % 2
center从0到2n-2
class Solution {
public int countSubstrings(String s) {
//中心拓展法
int ans = 0;
int n = s.length();
char[] str = s.toCharArray();
for(int center = 0; center < 2 * n - 1 ;center++ ){
int left = center / 2;
int right = left + center % 2;
while(left >=0 && right < n && str[left]==str[right]){
left--;
right++;
ans++;
}
}
return ans;
}
}
此方法也可以用来解leetcode 5:最长回文子串。
法2:动态规划
定义dp[i][j] 表示下标i与j之间的子串是否回文。
若s[i]==s[j],
当子串长度为1,2时,自然为回文子串
否则,若s[i+1]到s[j-1]为回文子串,则s[i]到s[j]为回文子串
于是有转移方程:
class Solution {
public int countSubstrings(String s) {
boolean[][] dp = new boolean[s.length()][s.length()];
int ans = 0;
char[] str = s.toCharArray();
for(int j=0;j<s.length();j++){
for(int i=0;i<=j;i++){
if(str[i]==str[j]&&(j - i < 2 || dp[i+1][j-1])){
ans++;
dp[i][j] = true;
}
}
}
return ans;
}
}