给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例 1:
输入: "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c".
示例 2:
输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".
注意:
输入的字符串长度不会超过1000。
方法一:暴力,枚举回文串的中心店即可。复杂度O(n^2)
class Solution {
public int countSubstrings(String s) {
int n=s.length();
int ans=n;
for(int i=1;i<n;i++) {
ans+=find(s,i-1,i+1,n);
if(s.charAt(i-1)==s.charAt(i))
ans+=find(s,i-1,i,n);
}
return ans;
}
private int find(String s,int l,int r,int n) {
int res=0;
while(l>=0 && r<n && s.charAt(l)==s.charAt(r)) {
res++;
l--;r++;
}
return res;
}
}
方法二:马拉车算法,不懂马拉车的可以看我马拉车讲解文章,相信大家肯定能看懂的。复杂度O(n)
class Solution {
public int countSubstrings(String s) {
char[] c=new char[2*s.length()+3];
c[0]='@'; c[1]='#'; c[c.length-1]='$';
int t=2;
for(char cc : s.toCharArray()) {
c[t++]=cc;
c[t++]='#';
}
int[] len=new int[c.length];
int center=0,right=0;
for(int i=1;i<len.length-1;i++) {
if(i<right)
len[i]=Math.min(right-i, len[2*center-i]);
while(c[i+len[i]+1]==c[i-len[i]-1])
len[i]++;
if(i+len[i]>right) {
center=i;
right=i+len[i];
}
}
int ans=0;
for(int v : len)
ans+=(v+1)/2;
return ans;
}
}