题目描述
给定一个字符串 s
,请计算这个字符串中有多少个回文子字符串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
输入:s = "abc"
输出:3
解释:三个回文子串: "a", "b", "c"
示例 2:
输入:s = "aaa"
输出:6
解释:6个回文子串: "a", "a", "a", "aa", "aa", "aaa"
提示:
1 <= s.length <= 1000
s
由小写英文字母组成
注意:本题与主站 647 题相同:https://leetcode.cn/problems/palindromic-substrings/
解法
方法一:从中心向两侧扩展回文串
我们可以枚举回文串的中间点,然后向左右两边扩展,统计回文串的数量。注意,回文串可能包含奇数个字符,也可能不包含。因此这两种情况都要考虑。
时间复杂度 $O(n^2)$,其中 $n$ 是字符串 s
的长度。
1
2
3
4
5
6
7
8
9
10
11
12
13 | class Solution:
def countSubstrings(self, s: str) -> int:
def f(i, j):
cnt = 0
while i >= 0 and j < n:
if s[i] != s[j]:
break
cnt += 1
i, j = i - 1, j + 1
return cnt
n = len(s)
return sum(f(i, i) + f(i, i + 1) for i in range(n))
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | class Solution {
private String s;
public int countSubstrings(String s) {
int ans = 0;
this.s = s;
for (int i = 0; i < s.length(); ++i) {
ans += f(i, i);
ans += f(i, i + 1);
}
return ans;
}
private int f(int i, int j) {
int cnt = 0;
for (; i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j); --i, ++j) {
++cnt;
}
return cnt;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | class Solution {
public:
int countSubstrings(string s) {
int ans = 0;
int n = s.size();
auto f = [&](int i, int j) -> int {
int cnt = 0;
for (; i >= 0 && j < n && s[i] == s[j]; --i, ++j) {
++cnt;
}
return cnt;
};
for (int i = 0; i < n; ++i) {
ans += f(i, i) + f(i, i + 1);
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | func countSubstrings(s string) (ans int) {
n := len(s)
f := func(i, j int) (cnt int) {
for ; i >= 0 && j < n && s[i] == s[j]; i, j = i-1, j+1 {
cnt++
}
return
}
for i := range s {
ans += f(i, i)
ans += f(i, i+1)
}
return
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | class Solution {
private var s: String = ""
func countSubstrings(_ s: String) -> Int {
var ans = 0
self.s = s
let length = s.count
for i in 0..<length {
ans += countPalindromes(i, i)
ans += countPalindromes(i, i + 1)
}
return ans
}
private func countPalindromes(_ i: Int, _ j: Int) -> Int {
var cnt = 0
var i = i
var j = j
let chars = Array(s)
while i >= 0 && j < chars.count && chars[i] == chars[j] {
cnt += 1
i -= 1
j += 1
}
return cnt
}
}
|
方法二:Manacher 算法
在 Manacher 算法的计算过程中,用 $p[i]-1$ 表示以第 $i$ 位为中心的最大回文长度,以第 $i$ 位为中心的回文串数量为 $\left \lceil \frac{p[i]-1}{2} \right \rceil$。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 s
的长度。