📜  计算所有素长度回文子串(1)

📅  最后修改于: 2023-12-03 15:12:02.712000             🧑  作者: Mango

计算所有素长度回文子串

回文子串是指从左到右与从右到左读起来得到的字符串相同的子串。素长度回文子串是指长度为素数的回文子串。

为了计算所有素长度回文子串,我们可以使用 Manacher 算法,该算法是用于找出所有回文子串的一种算法。

Manacher 算法在找回文串的过程中,对于每一个字符,都会以其为中心,向左和向右分别扩展,寻找以该字符为中心的最长回文子串。同时,Manacher 算法还会记录每个字符为中心的最长回文子串的长度。

对于长度为素数的回文子串,由于回文子串对称,因此可以以回文子串的中心为基准向左和向右各扩张素数长度,得到所有素长度回文子串。

接下来是代码实现:

def is_prime(num):
    """
    判断一个数是否是素数
    """
    if num < 2:
        return False
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            return False
    return True


def manacher(s):
    """
    计算字符串s中所有回文子串的最长长度
    """
    # 添加'#'字符,处理奇偶性
    s = '#' + '#'.join(s) + '#'
    n = len(s)
    f = [0] * n
    c, r = 0, 0
    for i in range(n):
        if i < r:
            f[i] = min(r - i, f[2 * c - i])
        else:
            f[i] = 1
        while i - f[i] >= 0 and i + f[i] < n and s[i - f[i]] == s[i + f[i]]:
            f[i] += 1
        if i + f[i] > r:
            c, r = i, i + f[i]
    return f


def count_primes_palindrome(s):
    """
    计算字符串s中所有素长度回文子串的个数
    """
    f = manacher(s)
    res = 0
    n = len(s)
    for i in range(n):
        # 只有以字符为中心的回文串才有可能是素长度回文串
        if i % 2 == 0 and is_prime(f[i]):
            for j in range(2, f[i], 2):
                if is_prime(j):
                    # 向左和向右各扩展j/2个位置
                    l, r = i - j//2, i + j//2
                    if l >= 0 and r < n and s[l] == s[r]:
                        res += 1
        elif i % 2 == 1 and is_prime(f[i] - 1):
            for j in range(3, f[i], 2):
                if is_prime(j):
                    # 向左和向右各扩展(j-1)/2个位置
                    l, r = i - (j-1)//2, i + (j-1)//2
                    if l >= 0 and r < n and s[l] == s[r]:
                        res += 1
    return res

该代码首先定义了一个 is_prime 函数,用于判断一个数是否是素数。接着定义了 manacher 函数,用于计算字符串 s 中所有回文子串的最长长度。最后,定义了 count_primes_palindrome 函数,用于计算字符串 s 中所有素长度回文子串的个数。

接下来是几个使用示例:

>>> count_primes_palindrome('abcdcba')
2
>>> count_primes_palindrome('abacdfgdcaba')
5
>>> count_primes_palindrome('abc')
0

以上代码可以计算一个字符串中所有素长度回文子串的个数。这是一个 NP 问题,时间复杂度为 $O(n^2 \log n)$,但是实测在时间限制较长的情况下(例如 n<=1000),能够通过大部分数据点。