回文子字符串的个数

90 阅读1分钟

image.png

代码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 % 2i := 0; i < 2 * n - 1; i++ 将两种情况一次处理

图片演示,假设 n 为 4

image.png

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
}