题目链接
解题思路
-
考虑下编辑距离的三种操作:插入,删除,修改,我们要得到更多的
UCC串,插入是最优的操作,删除是完全不操作的, 替换操作完全可以由插入操作代替,解释下为什么 -
以
UUC串为例,替换操作会改变成UCC, 而插入操作会得到UUCC,多一个字符对构造新的UCC串更优, 比如此时m=3,- 采取替换操作只能得到1个
UUC->UCC->UCCUC, - 而插入可以得到两个
UUC->UUCC->UCCUCC - 删除操作完全对答案没有贡献
- 采取替换操作只能得到1个
-
考虑如何操作最优,由上面可知,所有操作均采取插入。那么已经是
UCC的串不需要操作,直接记录, 后面插入也不对已经是UCC的串进行操作,因为对这些进行操作完全对答案不优 -
考虑只需要插入一次可以构成
UCC的情况有哪些?U*C*在C的前后都可以,那么只要是UC我们就可以花费代价1让ans加一*CC在 第一个C前面, 那么只要是CC就行- 字符只能使用一次,所有用后要记录他的使用状态
-
剩下的字符都需要进行两次操作才能得到
UCC -
我们可以使用变量记录当前已经操作的字符数量,
n-cnt就是剩下需要操作两次的字符数量
题解代码
int solution(int m, std::string s) {
//删除和替换等价于插入 对答案并不会产生额外贡献
//所以所有操作均为插入
int n = s.length();
vector<bool>use(n,false);
int cnt = 0;
int ans = 0;
//原本为UCC的串不变
for(int i=2; i<n; i++) {
string t = s.substr(i-2,3);
if(s.substr(i-2,3) =="UCC") {
use[i] =use[i-1] =use[i-2] = 1;
cnt+=3;
ans++;
}
}
// UC可以插入在C前后插入 UC* U*C
// CC在最前面插入 *CC
// 其他情况都需要两次
for(int i=1; i < n; i++) {
string t = s.substr(i-1,2);
//没有被使用过
if(!use[i] && !use[i-1] && m > 0) {
if(t == "UC" || t == "CC") {
use[i] = use[i-1] =1;
cnt+=2;
ans++;
m--;
}
}
}
//单个字符只要2次
ans += min(m / 2, n - cnt);
m -= min(m/2, n -cnt) *2;
//还能构成UCC
if(m > 2) {
ans+= m / 3;
}
return ans;
}
时间复杂度:
空间复杂度: