代码1:
暴力
- 枚举出所有的子串,然后再判断这些子串是否是回文;
func countSubstrings(s string) int {
ans := 0
n := len(s)
for a := 0; a < n; a++ {
for b := a; b < n; b++ {
if hw(s[a:b+1]) {
ans++
}
}
}
return ans
}
func hw(s string) bool {
a, b := 0, len(s)-1
for a <= b {
if s[a] == s[b] {
a++
b--
}else {
return false
}
}
return true
}
代码2:
- 枚举每一个可能的回文中心,然后用两个指针分别向左右两边拓展,当两个指针指向的元素相同的时候就拓展,否则停止拓展。
回文中心又需要分情况考虑,如果回文子串是奇数,自然只有一个中心,但如果是偶数,那么将会有两个回文中心
下面代码中,通过 l, r := i / 2, i / 2 + i % 2 和 i := 0; i < 2 * n - 1; i++ 将两种情况一次处理
图片演示,假设 n 为 4
func countSubstrings(s string) int {
n := len(s)
ans := 0
for i := 0; i < 2 * n - 1; i++ {
l, r := i / 2, i / 2 + i % 2
for l >= 0 && r < n && s[l] == s[r] {
l--
r++
ans++
}
}
return ans
}
代码3:
Manacher 算法
func countSubstrings(s string) int {
n := len(s)
t := "$#"
for i := 0; i < n; i++ {
t += string(s[i]) + "#"
}
n = len(t)
t += "!"
f := make([]int, n)
iMax, rMax, ans := 0, 0, 0
for i := 1; i < n; i++ {
// 初始化 f[i]
if i <= rMax {
f[i] = min(rMax - i + 1, f[2 * iMax - i])
} else {
f[i] = 1
}
// 中心拓展
for t[i + f[i]] == t[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
}
func min(x, y int) int {
if x < y {
return x
}
return y
}