
最少插入次数使字符串变为回文 是一个经典的动态规划问题。我们需要计算出通过最少的插入次数将给定的字符串转换为回文字符串。回文字符串是指正读和反读相同的字符串。通过动态规划的思想,我们可以高效地解决这一问题,分析每个字符与其对称位置之间的关系。
给定一个字符串 s,要求找到最少的插入步骤,使得这个字符串变为回文。
s 转换为回文所需的最小插入次数。"mbadm""mbdadbm" 或 "madbam"。如果我们要求插入最少次数,使得一个字符串变为回文,可以反过来思考:我们可以找到该字符串的 最长回文子序列,然后剩下的字符可以通过插入来补齐,从而形成一个回文。
dp[i][j],表示在区间 s[i...j] 内,将该子串变为回文所需的最少插入次数。
s[i] == s[j] 时,不需要插入,dp[i][j] = dp[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。i == j,即字符串长度为1时,已经是回文,不需要插入,因此 dp[i][i] = 0。i > j,这种情况不可能存在,值为 0。dp,dp[i][j] 记录了从 i 到 j 的子串所需的最少插入次数。dp 数组。dp[0][n-1] 中,n 是字符串的长度。initialize dp array with size n x n
for length from 2 to n:
for i from 0 to n-length:
j = i + length - 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]O(n^2),空间复杂度为 O(n^2)。以上就是让字符串成为回文串的最少插入次数问题的基本思路。
class Solution:
def minInsertions(self, s: str) -> int:
n = len(s)
# 初始化dp数组,dp[i][j] 表示将s[i:j+1]变为回文所需的最少插入次数
dp = [[0] * n for _ in range(n)]
# 从长度为2开始遍历子串
for length in range(2, n + 1):
for i in range(n - length + 1):
j = i + length - 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]dp 数组,dp[i][j] 表示将 s[i:j+1] 变为回文的最少插入次数。s[i] 和 s[j],根据状态转移方程更新 dp 数组。dp[0][n-1] 即为整个字符串变为回文的最少插入次数。class Solution {
public:
int minInsertions(string s) {
int n = s.size();
// 初始化dp数组,dp[i][j] 表示将s[i:j+1]变为回文所需的最少插入次数
vector<vector<int>> dp(n, vector<int>(n, 0));
// 从长度为2开始遍历子串
for (int length = 2; length <= n; ++length) {
for (int i = 0; i <= n - length; ++i) {
int j = i + length - 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];
}
};dp,dp[i][j] 表示将 s[i:j+1] 变为回文的最少插入次数。dp 数组。dp[0][n-1] 即为将整个字符串变为回文的最少插入次数。O(n^2),适合处理中等规模的字符串问题。