📌  相关文章
📜  最小删除要求的数量,以使任意数量的X都可以准确出现X次(1)

📅  最后修改于: 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 来表示一个空队列。