题目:1278. 分割回文串 III
思路:对于某一段字符串,将其修改为回文串的最少次数是可以通过动态规划得出的。
接着再通过动态规划得出:某一段划分为k个字符串,且满足均为回文串的最小次数。时间复杂度为0(n^3).
C++版本:
class Solution {
public:
int n=0;
vector<vector<int>> v;
//动态规划一:得出字符串修改为回文串的最小次数
void dp1(string s){
for(int lens=2;lens<=n;lens++){
for(int i=0;i+lens-1<n;i++){
int j=i+lens-1;
v[i][j]=v[i+1][j-1]+(s[i]!=s[j]);
}
}
}
//动态规划二:得出字符串修改为回文串的最小次数
void dp2(string s){
for(int i=n-2;i>=0;i--){
for(int j=i+1;j<n;j++){
v[i][j]=v[i+1][j-1]+(s[i]!=s[j]);
}
}
}
int palindromePartition(string s, int k) {
n=s.size();
v.assign(n,vector<int>(n,0));
dp1(s);
//dp2(s);
//动态规划三:某一段划分为k个字符串,且满足均为回文串的最小次数
//状态f[k][n]:再在区间[0,n]之间划分k次,且均为回文串的最小修改次数
vector<vector<int>> f(k,vector<int>(n,INT_MAX));
//当k=0时,表示不划分时,也就是整个字符串为回文串所需要修改的时间。
for(int i=0;i<n;i++){
f[0][i]=v[0][i];
}
//当k>0时
for(int ans=1;ans<k;ans++){
//i:第ans次切割后的最后一个区间的右端点
for(int i=ans;i<n;i++){
//j:第ans次切割后的最后一个区间的左端点
for(int j=i;j>=ans;j--)
//获得最优值:将区间[0,i]划分ans次,得到ans+1个字符串,且均为回文串的最小次数。
f[ans][i]=min(f[ans][i],f[ans-1][j-1]+v[j][i]);
}
}
return f[k-1][n-1];
}
};
JAVA版本:
class Solution {
int n=0;
int[][] v;
void dp1(char[] s){
for(int lens=2;lens<=n;lens++){
for(int i=0;i+lens-1<n;i++){
int j=i+lens-1;
v[i][j]=v[i+1][j-1]+(s[i]!=s[j] ? 1:0);
}
}
}
void dp2(char[] s){
for(int i=n-2;i>=0;i--){
for(int j=i+1;j<n;j++){
v[i][j]=v[i+1][j-1]+(s[i]!=s[j] ? 1:0);
}
}
}
public int palindromePartition(String s, int k) {
n=s.length();
v = new int[n][n];
char[] c=s.toCharArray();
dp1(c);
//dp2(c);
int[][] f = new int[k][n];
for(int[] x:f){
Arrays.fill(x,Integer.MAX_VALUE);
}
for(int i=0;i<n;i++){
f[0][i]=v[0][i];
}
for(int ans=1;ans<k;ans++){
for(int i=ans;i<n;i++){
for(int j=i;j>=ans;j--)
f[ans][i]=Math.min(f[ans][i],f[ans-1][j-1]+v[j][i]);
}
}
return f[k-1][n-1];
}
}