旺崽的博客

要么天赋异禀,要么天道酬勤

0%

LeetCode 995 K 连续位的最小翻转次数

题目链接

在仅包含 0 和 1 的数组 A 中,一次 K 位翻转包括选择一个长度为 K 的(连续)子数组,同时将子数组中的每个 0 更改为 1,而每个 1 更改为 0。

返回所需的 K 位翻转的最小次数,以便数组没有值为 0 的元素。如果不可能,返回 -1。

示例 1:

1
2
3
输入:A = [0,1,0], K = 1
输出:2
解释:先翻转 A[0],然后翻转 A[2]。

示例 2:

1
2
3
输入:A = [1,1,0], K = 2
输出:-1
解释:无论我们怎样翻转大小为 2 的子数组,我们都不能使数组变为 [1,1,1]。

示例 3:

1
2
3
4
5
6
输入:A = [0,0,0,1,0,1,1,0], K = 3
输出:3
解释:
翻转 A[0],A[1],A[2]: A变成 [1,1,1,1,0,1,1,0]
翻转 A[4],A[5],A[6]: A变成 [1,1,1,1,1,0,0,0]
翻转 A[5],A[6],A[7]: A变成 [1,1,1,1,1,1,1,1]

差分~
这种一次连续改 $k$ 位的题就是很经典的差分,我们只需要从左往右扫,碰到 $0$ 就改成 $1$ 即可,注意因为是连续修改,所以要用差分,线段树肯定也行,但是要麻烦许多,做完这题的可以类比牛客寒假训练营的一道题:题目链接,也是利用差分的性质,AC代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
int minKBitFlips(vector<int> &A, int K) {
vector<int> diff(A.size() + 1, 0);
int flag = 0, ans = 0;
for (int i = 0; i < A.size(); i++) {
flag += diff[i];
if (flag % 2) A[i] ^= 1;
if (i <= A.size() - K && !A[i]) {
A[i] = 1;
ans++;
diff[i]++;
diff[i + K]--;
flag++;
}
}
int sum = accumulate(A.begin(), A.end(), 0);
if (sum != A.size()) return -1;
return ans;
}
};