给定一个二进制数组 nums
和一个整数 k
。
k位翻转 就是从 nums
中选择一个长度为 k
的 子数组 ,同时把子数组中的每一个 0
都改成 1
,把子数组中的每一个 1
都改成 0
。
返回数组中不存在 0
所需的最小 k位翻转 次数。如果不可能,则返回 -1
。
子数组 是数组的 连续 部分。
示例 1:
输入:nums = [0,1,0], K = 1
输出:2
解释:先翻转 A[0],然后翻转 A[2]。
示例 2:
输入:nums = [1,1,0], K = 2
输出:-1
解释:无论我们怎样翻转大小为 2 的子数组,我们都不能使数组变为 [1,1,1]。
示例 3:
输入:nums = [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 <= nums.length <= 105
1 <= k <= nums.length
链接: 3995. K 连续位的最小翻转次数
题意好理解,就是每次翻转必须区间一起翻转。
按顺序向后遇到0就翻转,贪心思想。
最坏时间复杂度O(n)
树状数组
区间更新单点查询。
class BinIndexTree:
def __init__(self, size):
self.size = size
self.bin_tree = [0 for _ in range(size+5)]
def add(self,i,v):
while i<=self.size :
self.bin_tree[i] += v
i += self.lowbit(i)
def update(self,i,v):
val = v - (self.sum(i)-self.sum(i-1))
self.add(i,val)
def sum(self,i):
s = 0
while i >= 1:
s += self.bin_tree[i]
i -= self.lowbit(i)
return s
def lowbit(self,x):
return x&-x
def _point_query(self,i):
return self.sum(i)
def _interval_add(self,l,r,v):
self.add(l,v)
self.add(r+1,-v)
class Solution:
def minKBitFlips(self, nums: List[int], k: int) -> int:
"""
1.首先贪心地:向右遍历,对于每个0,以他为左端点翻转k个数。
2.这样最后遍历结束就是最小,最后失败就-1.
3.真的翻转就TLE,O(n*k)
4.不能真翻转的话其实是IUPQ,区间更新单点查询,类似树状数组的IUPQ,其实就是利用差分数组的思想
5.所以这题正解是差分数组或者滑窗。
6.滑窗就记录当前下标前k个数翻转了几次,用队列维护一个翻转过的下标窗口即可。队列长度是偶数等于没翻转。
7.那我用线段树是不是也能做啊
"""
n = len(nums)
flip = BinIndexTree(n)
ans = 0
for i in range(n-k+1):
# print(i,nums,flip.bin_tree,nums[i] ^ (flip._point_query(i+1)&1),ans)
if nums[i] ^ (flip._point_query(i+1)&1) == 1:
continue
ans += 1
# nums[i] = 1
flip._interval_add(i+1,i+k-1+1,1)
# print(nums)
for i in range(n-k+1,n):
if nums[i] ^ (flip._point_query(i+1)&1) == 0:
return -1
return ans
滑窗队列
class Solution:
def minKBitFlips(self, nums: List[int], k: int) -> int:
n = len(nums)
q = deque()
ans = 0
for i in range(n-k+1):
if q and q[0] <= i-k:
q.popleft()
if nums[i] ^ (len(q)&1) == 1:
continue
ans += 1
q.append(i)
for i in range(n-k+1,n):
if q and q[0] <= i-k:
q.popleft()
if nums[i] ^ (len(q)&1) == 0:
return -1
return ans