最少字符串操作次数 | 豆包MarsCode AI 刷题
问题描述
小U得到一个只包含小写字母的字符串 S。她可以执行如下操作:每次选择字符串中两个相同的字符删除,然后在字符串末尾添加一个任意的小写字母。小U想知道,最少需要多少次操作才能使得字符串中的所有字母都不相同
思路
一开始的思路是: 对于每个出现次数大于 1 的字符,每次可以消去两个相同字符并添加一个新字符,因此需要的操作次数为该字符出现次数的整除 2 的值(即 ),将所有出现次数大于 1 的字符需要的操作次数累加即可得到最终结果。
代码:
def solution(S: str) -> int:
# 创建一个字典来统计每个字符的出现次数
dic = {}
for c in S:
# 如果字符已经存在于字典中,增加其计数;否则初始化为1
dic[c] = dic.get(c, 0) + 1
# 对于每个频率v > 1的字符,计算v // 2并累加
return sum(v // 2 for v in dic.values() if v > 1)
上面的代码虽然可以AC,但并不完全正确,考虑下面的测试用例:
print(solution(S = "abcdefghijklmnopqrstuvwxyzaa") == 2) #False
代码返回的是 1 ,但实际上应该是 2 ,先去掉两个 a ,再添加一个 a ,然后再去掉两个 a 。其实是贪心策略有问题,贪心的最优策略应该是每次去找出现次数最高的字符 c ,把 c 的计数 -2 ,再去找出现次数最低的字符 c' ,把 c' 的计数 +1 。
-
为什么选择频次最高的字符?
- 字符
c的频次最高,意味着它对整体的重复程度影响最大。 - 如果不优先减少
c的数量,其他策略会导致更多重复字符,增加后续操作次数。
- 字符
-
为什么在移除两个字符后添加频次最低的字符?
-
添加频次最低的字符
d是为了尽量避免引入新的重复。例如:- 如果当前字符频次为
0,则添加它不会导致重复; - 如果当前字符频次非
0,则添加它也只会造成最少的重复量增加。
- 如果当前字符频次为
-
代码实现
import string
def solution(S: str) -> int:
ans = 0
#初始化字母表的所有计数为0
dic = {char: 0 for char in string.ascii_lowercase}
for c in S:
dic[c] += 1
#所有字符的出现次数全部小于等于1时即为答案
while not all(value <= 1 for value in dic.values()):
#出现次数最高的字符计数-2
max_key = max(dic, key=dic.get)
dic[max_key] -= 2
#出现次数最低的字符计数-1
min_key = min(dic, key=dic.get)
dic[min_key] += 1
ans += 1
return ans
if __name__ == '__main__':
#test cases...
复杂度分析
-
时间复杂度:
- 统计字符频次的时间复杂度为 ,其中 是字符串的长度。
- 每次查找频次最高和最低的字符在最坏情况下需要遍历字典 ,即常数时间。
- 最多进行 O(n) 次删除操作,因此总的时间复杂度为 。
-
空间复杂度:
- 需要一个大小为 26 的字典存储每个字母的频次,空间复杂度为 。