📅  最后修改于: 2023-12-03 15:42:02.775000             🧑  作者: Mango
给定一个由 0 和 1 组成的二进制字符串 s
以及整数 k
和 q
,逐次进行如下操作:
k
的子串,将其所有的 0 修改为 1。q
次上述操作。这是一个优化问题,首先需要考虑的是什么情况下更改 0 的数量会更少。显然,我们应该更改那些 0 的数量更多的子串。
我们可以通过一个累加辅助数组 prefix
来计算所有子串的 0 的数量。那么,如何才能找到 0 的数量前 k
多的子串呢?
我们可以使用一个大小为 k
的最小堆,对 prefix
进行扫描,每次将一个数加入堆中。当堆的大小超过 k
时,弹出堆顶元素,并将其从候选集合中删除。这样,最终堆中的元素就是前 k
大的数字。
接下来只需要遍历这些前 k
大的子串,对其中的每个子串进行更改,并统计修改后的二进制字符串中 0 的数量即可。
import heapq
class Solution:
def minimumNumberOfOperations(self, s: str, k: int, q: int) -> int:
n = len(s)
prefix = [0] * (n+1)
for i in range(1, n+1):
prefix[i] = prefix[i-1] + (1 if s[i-1] == '0' else 0)
ans = float('inf')
heap = []
for i in range(k, n+1):
p = prefix[i] - prefix[i-k]
heapq.heappush(heap, -p)
if len(heap) > k:
heapq.heappop(heap)
if len(heap) == k:
cost = -sum(heap)
operations = q * k
if cost <= operations:
ans = min(ans, n-cost)
return ans if ans != float('inf') else 0
#include <vector>
#include <queue>
using namespace std;
class Solution {
public:
int minimumNumberOfOperations(string s, int k, int q) {
int n = s.length();
vector<int> prefix(n+1);
for (int i = 1; i <= n; i++) {
prefix[i] = prefix[i-1] + (s[i-1] == '0' ? 1 : 0);
}
int ans = INT_MAX;
priority_queue<int> heap;
for (int i = k; i <= n; i++) {
int p = prefix[i] - prefix[i-k];
heap.push(p);
if (heap.size() > k) {
heap.pop();
}
if (heap.size() == k) {
int cost = -1 * accumulate(heap.begin(), heap.end(), 0);
int operations = q * k;
if (cost <= operations) {
ans = min(ans, n-cost);
}
}
}
return (ans == INT_MAX) ? 0 : ans;
}
};
时间复杂度为 $O(n \log k)$,其中 $n$ 是字符串的长度。我们需要扫描一遍 prefix
累加数组,然后对 prefix
进行 $n-k$ 次扫描,每次都要进行最多 $k$ 个元素的堆操作。