1 <= s.length <= 1000
s
由小写英文字母组成
class Solution {
public int countSubstrings(String s) {
//是回文,right++;不是,left++
int count=0;
int left=0;
while (left<s.length()) {
int right=left;
while (right<s.length()){
if(isPalindrome(s,left,right)){
count++;
}
right++;
}
left++;
}
return count;
}
private boolean isPalindrome(String s, int start, int end) {
while (start<end){
if(s.charAt(start)!=s.charAt(end)){
return false;
}
start++;end--;
}
return true;
}
}
枚举出所有的回文子串的两种思路:
- 枚举出所有的子串,然后再判断这些子串是否是回文;
O(n 2) 的时间枚举出所有的子串 s[l ⋯ r ],然后再用 O(r −l +1) 的时间检测当前的子串是否是回文,整个算法的时间复杂度是 O(n^3)。
- 枚举每一个可能的回文中心,然后用两个指针分别向左右两边拓展,当两个指针指向的元素相同的时候就拓展,否则停止拓展
枚举回文中心的是 O(n) 的,对于每个回文中心拓展的次数也是O(n) 的,所以时间复杂度是 O(n^2 )
class Solution {
public int countSubstrings(String s) {
int n = s.length(), ans = 0;
//长度为 n 的字符串会生成 2n−1 组回文中心
for (int i = 0; i < 2 * n - 1; ++i) {
int l = i / 2, r = i / 2 + i % 2;
while (l >= 0 && r < n && s.charAt(l) == s.charAt(r)) {
--l;
++r;
++ans;
}
}
return ans;
}
}
3、Manacher 算法
有什么浅显易懂的Manacher Algorithm讲解? - 知乎 (zhihu.com)
class Solution {
public int countSubstrings(String s) {
int n = s.length();
StringBuffer t = new StringBuffer("$#");
for (int i = 0; i < n; ++i) {
t.append(s.charAt(i));
t.append('#');
}
n = t.length();
t.append('!');
int[] f = new int[n];
int iMax = 0, rMax = 0, ans = 0;
for (int i = 1; i < n; ++i) {
// 初始化 f[i]
f[i] = i <= rMax ? Math.min(rMax - i + 1, f[2 * iMax - i]) : 1;
// 中心拓展
while (t.charAt(i + f[i]) == t.charAt(i - f[i])) {
++f[i];
}
// 动态维护 iMax 和 rMax
if (i + f[i] - 1 > rMax) {
iMax = i;
rMax = i + f[i] - 1;
}
// 统计答案, 当前贡献为 (f[i] - 1) / 2 上取整
ans += f[i] / 2;
}
return ans;
}
}