📜  门| GATE CS 2021 |设置 1 |问题 16(1)

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

门| GATE CS 2021 |设置 1 |问题 16

本文将介绍GATE CS 2021设置1的第16个问题,该问题涉及到了编程。

问题描述

给定一个字符串,为了检查它是否为回文,你可以在任意位置添加任意多个字符。例如,从字符串“racecar”开始,你可以添加一个字符'b'来得到“bracecar”,或添加一个字符'k'来得到“racecark”。你需要找到添加最少的字符来使给定的字符串成为回文。

解题思路

此问题可以通过动态规划来解决。定义一个二维数组dp[i][j],其中i和j分别表示字符串s的起始位置和终止位置。如果s[i:j]是回文串,则dp[i][j]为true。如果不是,则dp[i][j]为false。

根据回文串的定义,dp[i][j]为true的条件是dp[i+1][j-1]为true且s[i]==s[j]。

对于每个子问题,我们要么在字符串s的前面或后面添加一个字符,要么在字符串s的头或尾添加相同字符,以保持回文性。因此,我们可以通过以下方式来填充dp数组:

  • 初始化dp[i][i]为true,i为0到n-1(n为字符串s的长度)。
  • 对于所有i和j,如果i>j,则dp[i][j]=false。
  • 对于所有i和j,如果i<j,则dp[i][j]=dp[i+1][j-1] && s[i]==s[j]。

最后,我们需要找到最少的插入次数,使得整个字符串成为回文。我们可以使用双指针法得到答案。具体来说,我们设两个指针i和j,i从0开始指向字符串的左端,j从n-1开始指向字符串的右端。如果s[i]==s[j],则将i向右移动一位,j向左移动一位。否则,我们需要使用以下两种操作之一:

  • 在j和j-1之间插入s[i],i不变,j向左移动一位。
  • 在i和i+1之间插入s[j],i向右移动一位,j不变。

将两种操作中插入字符数的较小值加到计数器中,然后更新i和j。

代码实现

以下是使用Python实现以上算法的代码:

def minInsertions(s: str) -> int:
    n = len(s)
    dp = [[False] * n for _ in range(n)]
    for i in range(n):
        dp[i][i] = True
    for i in range(n - 1, -1, -1):
        for j in range(i + 1, n):
            if s[i] == s[j]:
                dp[i][j] = dp[i + 1][j - 1] if i + 1 < j else True
            else:
                dp[i][j] = i + 1 < j and dp[i + 1][j - 1]
    i, j = 0, n - 1
    ans = 0
    while i < j:
        if s[i] == s[j]:
            i += 1
            j -= 1
        elif dp[i + 1][j] and dp[i][j - 1]:
            ans += 1
            i += 1
            j -= 1
        elif dp[i + 1][j]:
            ans += 1
            i += 1
        else:
            ans += 1
            j -= 1
    return ans

以上代码的时间复杂度为$O(n^2)$,空间复杂度为$O(n^2)$,其中$n$为字符串s的长度。