一、题目
给定一个字符串 str,如果可以在 str 的任意位置添加字符,请返回在添加字符最少的情况下,让 str 整体都是回文字符串的一种结果
1 | str="ABA",str 本身就是回文串,不需要添加字符,所以返回 “ABA” |
leetcode 题目:https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/
二、分析
使用动态规划的方式,如果 str 的长度为 N,因此动态规划表是一个 N*N
的矩阵。dp[i][j]
值的含义代表子串 str[i...j]
最少添加几个字符可以使 str[i...j]
整体都是回文串。那么。如果求 dp[i][j]
的值,有如下三种情况:
- 如果字符串
str[i...j]
只有一个字符,那么此时str[i...j]
已经是回文字符串了,此时dp[i][j]=0
- 如果字符串
str[i...j]
只有两个字符。如果两个字符相等,那么dp[i][j]=0
。如果两个字符不相等,只用添加一个字符就可以使str[i...j]
变成回文串,那么dp[i][j]=1
。 - 如果字符串
str[i...j]
多于两个字符,如果str[i]==str[j]
,那么dp[i][j]=dp[i+1][j-1]
。如果str[i]!=str[j]
,那么要让str[i...j]
整体变为回文串有两种方法。- 一种方法是让
str[i...j-1]
先变成回文串,然后在左边加上字符str[j]
- 另一种方法是让
str[i+1...j]
先变成回文串,然后在右边加上字符str[i]
。 - 这两种方法那个代价最小就选哪个,即
dp[i][j] = min(dp[i][j-1], dp[i+1][j]) + 1
- 一种方法是让
如上 i 代表的是横轴,j 代表的是纵轴。并且 i 代表字符串的左边,j 代表字符串的右边。因此 i 一定是小于等于 j 的值。
所以对于这个二维数组,我们只需要关注右上部分即可。所以如下:
1 | std::vector<std::vector<int>> get_dp(const std::string& str) { |
我们即可求出:让字符串成为回文串的最少插入次数,此结果存储在 dp[0][str.size()-1]
位置。
接着,我们再来让字符串成为回文串,先准备一个结果字符串,这个字符串的长度为:str.size() + dp[0][str.size()-1]
使用四个变量,i,j 分别表示原始字符串的最左边和最右边;res_left 和 res_right 分别表示结果字符串的最左边和最右边。我们从左到右遍历原始字符串。每次判断 str[i]
是否等于 str[j]
。
- 如果相等,则直接在结果字符串中添加
str[i]
和str[j]
- 如果不相等,则需要通过 dp 数组来看
dp[i+1][j]
比较小,还是dp[i][j-1]
比较小。选择较小的那个去添加字符。
如下代码:
1 | #include <vector> |