📅  最后修改于: 2023-12-03 15:40:15.451000             🧑  作者: Mango
我们有一个字符串只包含字符 'X' 和 'Y',我们要将 'X' 出现的次数准确地变成一个给定的数字 n。但是,我们也可以删除一些字符,使得最终的字符串满足该要求。求最少需要删除多少个字符。
我们可以对每个位置计算,将该位置字符设为 'X' 时最少需要删除多少个字符,最后取所有位置结果的最小值即为所求。
具体的,我们考虑从左到右地遍历字符串。在遍历到第 i 位时,我们需要将前缀的字符 'X' 的个数变为 cnt[i]。我们设 have[i] 表示第 i 位之前已经出现的字符 'X' 的个数,则如果要将前缀的字符 'X' 的个数变为 cnt[i],我们需要删除的字符数就应该是 del[i] = max(0, have[i] - cnt[i])。
接下来我们考虑如何计算 have[i]。显然 have[i] = have[i-1] + (s[i] == 'X')。我们考虑只保留 have[i] ≥ cnt[i] 的前缀的贡献,即令 have[i] = max(have[j]),其中 j ∈ [0, i] 且 have[j] ≥ cnt[i]。
因为对于任意 j1 < j2,有 have[j1] ≤ have[j2],因此将 cnt 升序排序,可以保证每次计算 have[i] 时前面的 have[j] 都是有序的。这启示我们可以使用单调队列来维护 max(have[j])。
总时间复杂度是 O(nlogn)。
def min_deletions(s: str, n: int) -> int:
cnt = [s.count('X', 0, i+1) for i in range(len(s))]
have = [0] * len(s)
dels = [0] * len(s)
que = []
for i in range(len(s)):
heapq.heappush(que, float('-inf'))
while que and que[0] < cnt[i]:
heapq.heappop(que)
while que and que[-1] > have[i]:
que.pop()
have[i] = max(have[i], que[0])
dels[i] = max(0, have[i] - cnt[i])
heapq.heappush(que, have[i])
return sum(dels)
代码中我们使用了 heapq 来实现单调队列。注意这里为了方便使用 -inf
来表示一个空队列。