📜  查找字符串是否为K回文|套装1(1)

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

查找字符串是否为K回文 | 套装1

本套装包含了多个解决方案,用于判断一个字符串是否为K回文字符串(即最多删除K个字符可以得到回文字符串)。以下是各个方案及其使用方法。

动态规划

动态规划是一个常见的解决字符串问题的方法,也适用于判断回文字符串。我们可以使用一个二维数组dp[i][j]表示字符串从下标i到下标j是否为回文字符串,然后根据状态转移方程进行推导。

def is_k_palindrome_dp(s: str, k: int) -> bool:
    n = len(s)
    dp = [[False] * n for _ in range(n)]
    
    for i in range(n):
        dp[i][i] = True
        
    for j in range(1, n):
        for i in range(j):
            if s[i] == s[j]:
                dp[i][j] = dp[i+1][j-1] if j - i > 1 else True
            else:
                dp[i][j] = False
                
    count = sum(1 for i in range(n) for j in range(n) if dp[i][j] is True)
    
    return count >= 2 * k + 1 - n
时间复杂度

时间复杂度为$O(n^2)$,其中$n$是字符串的长度。

空间复杂度

空间复杂度为$O(n^2)$,其中$n$是字符串的长度。

双指针法

我们可以使用双指针,从字符串的两端开始判断是否为回文字符串。当遇到不同字符时,我们可以删除其中一个字符继续判断,直到删除$k$个字符或者整个字符串都已经被判断为回文字符串为止。

def is_k_palindrome_two_pointers(s: str, k: int) -> bool:
    def is_palindrome(string: str, left: int, right: int) -> bool:
        while left < right:
            if string[left] != string[right]:
                return False
            left += 1
            right -= 1
        return True
    
    left, right = 0, len(s) - 1
    
    while left < right:
        if s[left] != s[right]:
            if k == 0:
                return False
            if is_palindrome(s, left + 1, right):
                return True
            if is_palindrome(s, left, right - 1):
                return True
            return False
        left += 1
        right -= 1
    
    return True
时间复杂度

时间复杂度为$O(n^2)$,其中$n$是字符串的长度。

空间复杂度

空间复杂度为$O(1)$,常数较小。

中心扩散法

中心扩散法是一种判断回文字符串的方法,我们可以考虑从一个字符或者两个字符开始,不断向两边扩张,直到不能再扩为止。当遇到不同字符时,我们可以删除其中一个字符继续判断,直到删除$k$个字符或者整个字符串都已经被判断为回文字符串为止。

def is_k_palindrome_center(s: str, k: int) -> bool:
    def expand(string: str, left: int, right: int) -> int:
        while left >= 0 and right < len(string) and string[left] == string[right]:
            left -= 1
            right += 1
        return right - left - 1
    
    if len(s) <= 1:
        return True
    
    count = 0
    
    for i in range(len(s)):
        length1, length2 = expand(s, i, i), expand(s, i, i+1)
        length = max(length1, length2)
        count += (length + 1) // 2 - 1
        if count > k:
            return False
    
    return True
时间复杂度

时间复杂度为$O(n^2)$,其中$n$是字符串的长度。

空间复杂度

空间复杂度为$O(1)$,常数较小。

Manacher算法

Manacher算法是一种高效的求解最长回文子串的方法,我们可以通过在原字符串中插入特殊字符,将奇偶性处理为同一种情况,然后使用Manacher算法求出其最长回文子串。最后判断删除$k$个字符是否可以得到一个回文字符串即可。

def is_k_palindrome_manacher(s: str, k: int) -> bool:
    def manacher(string: str) -> str:
        new_string = '@#' + "#".join(string) + '#$'
        radius = [0] * len(new_string)
        center, max_right = 0, 0
        
        for i in range(1, len(new_string)-1):
            if i < max_right:
                radius[i] = min(radius[2*center-i], max_right-i)
            
            while new_string[i+radius[i]+1] == new_string[i-radius[i]-1]:
                radius[i] += 1
            
            if i + radius[i] > max_right:
                center, max_right = i, i + radius[i]
        
        index = radius.index(max(radius))
        return new_string[index-radius[index]:index+radius[index]+1].replace('#', '')
    
    new_s = manacher(s)
    
    return len(new_s) - sum(1 for i in range(len(s)) if s[i] != new_s[i]) <= 2 * k
时间复杂度

时间复杂度为$O(n)$,其中$n$是字符串的长度。

空间复杂度

空间复杂度为$O(n)$,需要额外使用一个数组来表示当前位置的最长回文半径。