📌  相关文章
📜  生成字符串回文的最小删除次数(1)

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

生成字符串回文的最小删除次数

对于给定的字符串,我们可以通过删除某些字符使其变成回文串。回文串是正序和倒序读取相同的字符串。求生成回文串的最小删除次数。

一个简单的方法是通过求最长公共子序列(LCS)来找到字符串的最长回文子序列(LPS),然后用原始字符串的长度减去LPS的长度即可得出最小删除次数。但是这个方法的时间复杂度为O(n^2),并不能满足大部分的数据,尤其是字符串长度很长的情况。

动态规划

更为高效的方法是使用动态规划。我们可以定义一个二维数组dp,其中dp[i][j]表示从i到j的子串生成回文串的最小删除次数。 如果s[i]==s[j],则dp[i][j] = dp[i+1][j-1],因为第i个字符和第j个字符可以成为回文,同时前i+1到j-1的子串也可以成为回文,所以将i和j两个字符匹配后,等同于解决了i+1到j-1的问题,不需要额外的删除操作。 如果s[i]!=s[j],则有两个选择:要么保留s[i],删去s[j],然后dp[i][j] = dp[i][j-1] + 1; 要么保留s[j],删去s[i],然后dp[i][j] = dp[i+1][j] + 1;(+1是因为删除了一个字符)。我们选择删除次数更小的方案。

def min_delete(s: str) -> int:
    n = len(s)
    dp = [[0 for _ in range(n)] for _ in range(n)]  # 初始化dp数组
    for i in range(n-2, -1, -1):
        for j in range(i+1, n):
            if s[i] == s[j]:
                dp[i][j] = dp[i+1][j-1]
            else:
                dp[i][j] = min(dp[i+1][j], dp[i][j-1]) + 1
    return dp[0][n-1]

代码使用了O(n^2)的时间和空间,可以通过空间优化将空间复杂度降至O(n)。

def min_delete(s: str) -> int:
    n = len(s)
    dp = [0] * n
    for i in range(n-2, -1, -1):
        pre = 0
        for j in range(i+1, n):
            temp = dp[j]
            if s[i] == s[j]:
                dp[j] = pre
            else:
                dp[j] = min(dp[j], dp[j-1]) + 1
            pre = temp
    return dp[n-1]
测试样例
assert min_delete("abcda") == 2
assert min_delete("bxxb") == 1
assert min_delete("xxnknxx") == 2