问题描述
小M有一个字符串,他希望通过删除最少的字符将其转化为一个“神奇字符串”。所谓“神奇字符串”满足以下两个条件:
- 它的长度是3的倍数。
- 对于任意的下标
i
,其中i
是3的倍数(即i = 3x
),都必须满足S[i] = S[i+1] = S[i+2]
。
例如,给定字符串aabca
,我们可以通过删除两个字符,将其变为aaa
,这是一个符合条件的“神奇字符串”。
测试样例
样例1:
输入:
S = "aabca"
输出:2
样例2:
输入:
S = "abcdef"
输出:6
样例3:
输入:
S = "aaabbbccc"
输出:0
题解:
最后的结构就应该像样例3里的一样,每3个相同的连在一起。于是使用动态规划,DP[i]代表第i个字符是结尾时的最少需要切割的次数。
于是从第i位开始往后遍历,当遇到重复的就cnt++,遇到不相同的就cut++,当重复的字符个数到达3个时,就推出循环,记录当前的j值。
其中cnt记录了重复的个数用来判断推出条件,cut记录切除的字符的个数,而DP[j-1]则是前面得到神奇字符串最小需要的次数。
状态转移:
注意:需提前DP[i]=DP[i-1]+1。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
#include<map>
#include<set>
using namespace std;
int solution(string S) {
vector<int> dp(S.size()+2,0);
for(int i=0;i<S.size();i++){
dp[i+1]=dp[i]+1;
int cut=0;
int cnt=1;
int numj=0;
for(int j=i-1;j>=0;j--){
if(S[j]==S[i]){
cnt++;
if(cnt==3){
numj=j;
break;
}
}
else{
cut++;
}
}
if(cnt==3){
//cout << numj << "\n";
dp[i+1]=min(dp[i+1],dp[numj]+cut);
}
}
/*
for(int i=0;i<=S.size();i++){
cout << dp[i] << " ";
}
cout << "\n";
*/
return dp[S.size()];
}
int main() {
cout << (solution("aabca") == 2) << endl;
cout << (solution("abcdef") == 6) << endl;
cout << (solution("aaabbbccc") == 0) << endl;
cout << (solution("aabcacdbbaaca") == 7) << endl;
return 0;
}