贪心:最大UCC字串计算 | 豆包MarsCodeAI刷题

117 阅读2分钟

题目链接

最大UCC字串计算

解题思路

  • 考虑下编辑距离的三种操作:插入,删除,修改,我们要得到更多的UCC串,插入是最优的操作,删除是完全不操作的, 替换操作完全可以由插入操作代替,解释下为什么

  • UUC串为例,替换操作会改变成UCC, 而插入操作会得到UUCC,多一个字符对构造新的UCC串更优, 比如此时m=3

    • 采取替换操作只能得到1个UUC -> UCC -> UCCUC
    • 而插入可以得到两个UUC ->UUCC -> UCCUCC
    • 删除操作完全对答案没有贡献
  • 考虑如何操作最优,由上面可知,所有操作均采取插入。那么已经是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;

}

时间复杂度: O(n)O(n)
空间复杂度: O(n)O(n)