leetcode 1312

问题

Given a string s. In one step you can insert any character at any index of the string.

Return the minimum number of steps to make s palindrome.

A Palindrome String is one that reads the same backward as well as forward.

Example 1:

1
2
3
Input: s = "zzazz"
Output: 0
Explanation: The string "zzazz" is already palindrome we don't need any insertions.

Example 2:

1
2
3
Input: s = "mbadm"
Output: 2
Explanation: String can be "mbdadbm" or "mdbabdm".

Example 3:

1
2
3
Input: s = "leetcode"
Output: 5
Explanation: Inserting 5 characters the string becomes "leetcodocteel".

Example 4:

1
2
Input: s = "g"
Output: 0

Example 5:

1
2
Input: s = "no"
Output: 1

Constraints:

  • 1 <= s.length <= 500
  • All characters of s are lower case English letters.

分析

思路1: 将 string s 反转得到 string ts ,然后求最长公共子序列,再由 s.size() 减去最长公共子序列的长度得到答案。

思路2: 先来考虑 s 是回文串的情况。当 s 是回文时,我们假设两个首尾指针 ij ,分别指向 s 的头和尾,当 s[i] == s[j] 时,i++, j--; 直到不满足 i < j 的条件。于是,由此可以引申到本题的处理。在本题中声明两个首尾指针 ij ,分别指向 s 的头和尾,当 s[i] == s[j] 时,i++, j--; ;当有 s[i] != s[j] 时,就需要通过插入字符来保证 s 变成一个回文。这时,插入字符的位置就有两种情况,在 i 的位置插入 s[j] 或者在 j 的位置插入 s[i]。这样问题就分解成了子问题。假设 $dp[i][j]$ 表示子串 s[i...j] 形成子串的最小插入字符数量。后期优化状态压缩?

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
int helper(const string &s, const string &t) {
int m = s.size();
int n = t.size();
vector<vector<int>> dp(m, vector<int>(n, 0));
if (s[0] == t[0]) dp[0][0] = 1;
for (int j = 1; j < n; ++j) {
if (s[0] == t[j]) dp[0][j] = 1;
else dp[0][j] = dp[0][j-1];
}
for (int i = 1; i < m; ++i) {
if (s[i] == t[0]) dp[i][0] = 1;
else dp[i][0] = dp[i-1][0];
}
for (int i = 1; i < m; ++i) {
for (int j = 1; j < n; ++j) {
if(s[i] == t[j])
dp[i][j] = dp[i-1][j-1] + 1;
else
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return dp[m-1][n-1];
}

int minInsertions(string s) {
string ts = s;
reverse(ts.begin(), ts.end());
return s.size() - helper(s, ts);
}
};

代码2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
int helper(const string &s, vector<vector<int>> &dp, int i, int j) {
if (i >= j) return 0;
if (dp[i][j] >= 0) return dp[i][j];
while (i < j && s[i] == s[j]) {
i++;
j--;
}
if (i >= j) return 0;
return dp[i][j] = 1+min(helper(s, dp, i+1, j), helper(s, dp, i, j-1));
}
int minInsertions(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, -1));
return helper(s, dp, 0, s.size()-1);
}
};

代码3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
int minInsertions(string s) {
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n, -1));

dp[0][0] = 0;
for (int i = 1; i < n; ++i) {
dp[i][i] = 0;
dp[i-1][i] = s[i-1]==s[i]? 0: 1;
}

for (int len = 3; len <= n; ++len) {
for (int i = 0; i < n-len+1; ++i) {
int j = i+len-1;
dp[i][j] = s[i]==s[j]? dp[i+1][j-1]: 1+min(dp[i+1][j], dp[i][j-1]);
}
}

return dp[0][n-1];
}
};