题解——22. 最少字符串操作次数 | 豆包MarsCode AI刷题

94 阅读4分钟

原题截图

image.png

题意分析

阅读题目可知,本题的目标是使字符串中所有字母都不相同,并且在对字符串进行操作时,可以选取任意位置的两个相同字符删除,所以在本题的字符串中,字符所在的位置是不重要的,因此可以把本题中的字符串抽象为一个字符的可重集合。经过上述抽象,去除非关键信息后的题意如下。

有一个只包含小写字母的可重集合SS,可以进行如下操作:将SS中的两个相同的字符删除,同时向SS中加入任意的一个小写字母,问最少多少次操作可以使集合中每个元素都不相同。

解题思路

本题是一个思维题,虽然不涉及任何高级算法,但需要仔细分析题意以及策略,才能准确地得出答案。本题的解题关键为,在删除两个相同字符后,添加什么字符是最优的。经过分析可知,如果添加一个字符串中已有的字符(设为c),则后续一定需要至少一次从字符串中删除两个c(并加入一个字符)的操作,才能使最终的字符串满足题意;但如果添加一个字符串中当前没有的字符(设为d),并且进行某种记录,保证后续尽可能不向字符串中放入字符d,就可以避免额外增加一次操作。

综上所述,在需要放入一个字符时,要尽可能放入字符串中当前没有的字符,除非当前字符串中已经有全部的26个小写字母。

最后分析需要放入字符时,字符串中已有全部26个小写字母的情况。经过分析可知,此时添加什么字符是不重要的,因为此时添加任何一个字符(设为x),都会增加一次必须进行的删除两个x(并加入一个字符)的操作。

如果仅得出上述结论,就去编写完全模拟上述过程的代码,写出的程序不仅时间复杂度高,而且代码量可能也不会太少。所以可以进一步化简上述过程,经过进一步分析,可知如果不考虑新放入的字符,删除字符和放入字符可以分别独立进行;并且二者独立进行也不会影响最优策略的得出,因为加入新字符只会使后续需要进行的操作次数增加或不变,而不可能使后续需要进行的操作次数减小,而加入新字符前的删除两个相同的字符的操作又是无论如何也不可避免的。

所以可以得出如下策略:首先可以先从字符串中取出尽可能多的“两个相同的字符”,并且先不加入新字符,并记录进行“取出两个相同的字符”的操作的次数(设为sum)。此时可以很容易地得出接下来的策略,首先将字符串中没有的那些小写字母放入,然后对于剩余没有放入的字符,每放入一个字符(可随意选择,设放入的字符为k),就进行一次“取出2个k,放入一个k”的操作。

这样,我们就可以在最开始记录个数为奇数的字母的个数(设为cnto),cnto即为尽可能取出所有的两个相同的字符后,字符串中剩余的字符的个数;sum-cnto即为尽可能取出所有的两个相同的字符后,字符串中没有的那些小写字母的个数;max(0, sum-cnto)即为尽可能取出所有的两个相同的字符,并将字符串中没有的那些小写字母放入后,需要进行的“放入的字符k,再‘取出2个k,放入一个k’”的操作的次数;最后,sum + max(0, sum-cnto)即为需要进行的操作的总次数。

代码实现

#include <bits/stdc++.h>
using namespace std;
int solution(const std::string& s)
{
    int cnto=0, sum=0;
    char cnt[128]={};
    for(auto&& i:s) cnt[(int)i]++;
    for(int i='a';i<='z';i++)
    {
        if((cnt[i]&1) == 0) cnto++;
        sum += cnt[i]>>1;
    }
    return sum + max(0, sum-cnto);
}

总结

本题是一道不涉及任何高级算法的思维题,设字符串长度为nn,则本解法的时间复杂度O(n)O(n),空间复杂度为O(1)O(1)(数组大小为128是固定值,与其他变量无关,所以空间复杂度为常数),如果你有复杂度更优的解法,欢迎在下方评论。