在仅包含 0 和 1 的数组 A 中,一次 K 位翻转包括选择一个长度为 K 的(连续)子数组,同时将子数组中的每个 0 更改为 1,而每个 1 更改为 0。
返回所需的 K 位翻转的最小次数,以便数组没有值为 0 的元素。如果不可能,返回 -1。
示例 1:
输入:A = [0,1,0], K = 1
输出:2
解释:先翻转 A[0],然后翻转 A[2]。
示例 2:
输入:A = [1,1,0], K = 2
输出:-1
解释:无论我们怎样翻转大小为 2 的子数组,我们都不能使数组变为 [1,1,1]。
示例 3:
输入: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]
提示:
1 <= A.length <= 30000
1 <= K <= A.length
妄想暴力逃课:
从左到右遍历数组,如果碰到一个 0,以其为左端进行翻转,并修改当前位置开始的长度为 k 的子数组,同时计数器 + 1,最终如果数组不全为 0 则返回 -1 ,否则返回计数器的值。
class Solution:
def minKBitFlips(self, A, K):
N = len(A)
res = 0
for i in range(N - K + 1):
if A[i] == 1:
continue
for j in range(K):
A[i + j] ^= 1
ans += 1
for k in range(N):
if A[k] == 0:
return -1
return res
ps: 但是没逃成功,超时了。。。
老老实实学习官方做法:
差分法
class Solution:
def minKBitFlips(self, A: List[int], K: int) -> int:
n, count, res = len(A), 0, 0
diff = [0] * (n + 1) # 考虑边界问题,这里需要多1个。
for i in range(n):
count += diff[i] # 先计算 第 i 个位置翻转的次数
if (count + A[i]) % 2 == 0: # 翻转count次后 还是不为1 的话就 再翻转一次[i:i+k-1]区间 如果越界就返回实现不了-1;
if i + K > n:
return -1
diff[i + K] -= 1 # 如果要多翻转一次,那么这里count+1 同时diff[i+k] 因为 A[i+k-1]多翻转了一次 ,所以之差 -1
count += 1
res += 1
return res