📜  形成回文的最小插入数| DP-28(1)

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

题目介绍

给定一个字符串,添加最少的字符使其成为回文字符串,然后返回添加的字符数。

例如,如果给定的字符串是 "abcd",所需的最小插入操作是 "dcba",因此需要添加 3 个字符。

解题思路

我们可以使用动态规划的思路来解决这个问题。

假设我们有字符串 $s$ ,我们可以使用以下方法来插入字符以形成回文字符串:

  • 在 $s$ 的开头或结尾处插入一个字符(即添加到左侧或右侧)
  • 如果第一个和最后一个字符相同,则它们已经匹配,并且我们可以递归地处理剩余的子字符串 $s [1:n-1]$。

因此,我们可以将原问题转换为子问题,并考虑如何使用子问题的解来求解原问题。

假设 $dp[i][j]$ 表示从 $i$ 到 $j$ 的子字符串所需的最小插入次数。如果 $s[i]$ 与 $s[j]$ 匹配,则不需要插入任何字符并将问题转化为子问题 $dp[i+1][j-1]$。如果 $s[i]$ 与 $s[j]$ 不匹配,则它们两个必须添加到字符串中,并且我们需要递归地解决子问题 $dp[i+1][j]$ 和 $dp[i][j-1]$。在这两种情况下,我们最终需要选择插入最少数量的字符。

因为我们需要访问 $dp[i+1][j-1]$、$dp[i+1][j]$、$dp[i][j-1]$,因此我们可以使用bottom-up方法,先计算小的子问题,然后利用它们来计算大问题。

在该算法的实现中,我们可以使用二维动态数组 $dp$ 来保存子问题的解,并填充数组以计算 $dp[0][n-1]$,其中 $n$ 是字符串的长度。

代码实现

def min_insertions(s: str) -> int:
    n = len(s)
    dp = [[0] * n for _ in range(n)]

    # 先枚举子串长度 l
    for l in range(2, n + 1):
        # 枚举子串起始位置 i
        for i in range(n - l + 1):
            j = i + l - 1
            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]

总结

这道题目是一道典型的动态规划问题,需要我们将原问题转化为子问题并使用bottom-up的方法来解决。在本题的实现中,我们使用二维数组来保存子问题的解,并使用双指针的方式枚举子串的长度和起始位置,最终计算出 $dp[0][n-1]$ 即为答案。

(完)