题意
有一个特殊的printer,每次可以从任意位置输出任意长度相同字符,但是会覆盖之前的输出,现在给一个字符串,问需要最少多少次能输出这个字符串。
题解
对于一个字符串:
- 直接分成前后两部分输出
- 如果首尾字符相同,那么可以先输出整个字符串长度的首字符。然后再输出中间的字符。
那么另 dp[i][j] d p [ i ] [ j ] 表示输出i到j这一部分的字符串需要的最少次数,那么:
- dp[i][j]=mink(dp[i][k]+d[k+1][j]) d p [ i ] [ j ] = min k ( d p [ i ] [ k ] + d [ k + 1 ] [ j ] )
- dp[i][j]=mink(dp[i][k]+d[k][j]−1),when s[i]==s[k]==s[j] d p [ i ] [ j ] = min k ( d p [ i ] [ k ] + d [ k ] [ j ] − 1 ) , w h e n s [ i ] == s [ k ] == s [ j ]
最后 dp[i][j] d p [ i ] [ j ] 取1、2的最小值就行,用记忆化搜索来做。
代码
class Solution {
public:
int strangePrinter(string s) {
vector<vector<int>> dp(s.size(), vector<int>(s.size(), -1));
return dfs(0, s.size() - 1, dp, s);
}
int dfs(int st, int ed, vector<vector<int>> &dp, string &s) {
if (st == ed) {
return 1;
}
if (st > ed) {
return 0;
}
if (st + 1 == ed && s[st] == s[ed]) {
return 1;
}
if (dp[st][ed] != -1) {
return dp[st][ed];
}
int ans = 1e8;
for (int i = st; i < ed; i++) {
ans = min(ans, dfs(st, i, dp, s) + dfs(i + 1, ed, dp, s));
}
if (s[st] == s[ed]) {
ans = min(ans, dfs(st + 1, ed - 1, dp, s) + 1);
for (int i = st + 1; i < ed; i++) {
if (s[i] == s[st]) {
ans = min(ans, dfs(st, i, dp, s) + dfs(i, ed, dp, s) - 1);
}
}
}
return dp[st][ed] = ans;
}
};