# 995. Minimum Number of K Consecutive Bit Flips

**<font color=red>难度: hard</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/minimum-number-of-k-consecutive-bit-flips/

> 内容描述

```
In an array A containing only 0s and 1s, a K-bit flip consists of choosing a (contiguous) subarray of length K and simultaneously changing every 0 in the subarray to 1, and every 1 in the subarray to 0.

Return the minimum number of K-bit flips required so that there is no 0 in the array.  If it is not possible, return -1.

 

Example 1:

Input: A = [0,1,0], K = 1
Output: 2
Explanation: Flip A[0], then flip A[2].
Example 2:

Input: A = [1,1,0], K = 2
Output: -1
Explanation: No matter how we flip subarrays of size 2, we can't make the array become [1,1,1].
Example 3:

Input: A = [0,0,0,1,0,1,1,0], K = 3
Output: 3
Explanation:
Flip A[0],A[1],A[2]: A becomes [1,1,1,1,0,1,1,0]
Flip A[4],A[5],A[6]: A becomes [1,1,1,1,1,0,0,0]
Flip A[5],A[6],A[7]: A becomes [1,1,1,1,1,1,1,1]
 

Note:

1 <= A.length <= 30000
1 <= K <= A.length
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******


如果A[0]是0的话，我们是一定要先将它变成1的，因此我们每次找到左边第1个0，然后开始flip，但是真实的flip会消耗很多时间，所以我们可以模拟flip

假设我们在A[i]这个点flip了一次的话，那么我们就要知道A[i]这个点flip的效果在A[i+K]这个点就会消失，期间所有的点都会受到影响（即flip一次）

因此我们维护一个之前需要flip的次数need，即i前面的点给i点造成的flip效果次数

然后维护一个close列表，close[i]为True代表i点会消失一次flip的效果（前面已经描述过了）

对于i点来说，
- 如果A[i]是0，并且之前需要flip的次数为偶数的话，i点就真的需要flip一次
- 如果A[i]是1，并且之前需要flip的次数为奇数的话，i点就真的需要flip一次
- 其余情况i点都不需要flip

注意：如果i点需要flip，但是它后面压根没有K个元素了（包含i点本身），那么说明我们无法flip成功


```python
class Solution:
    def minKBitFlips(self, A: 'List[int]', K: 'int') -> 'int':
        close = [False] * len(A)
        res, need = 0, 0
        for i in range(len(A)):
            if close[i]:
                need -= 1
            if (A[i] == 1 and need % 2 == 1) or (A[i] == 0 and need % 2 == 0):
                res += 1
                need += 1
                if i + K - 1 > len(A) - 1:
                    return -1
                if i + K < len(A):
                    close[i+K] = True # 因为i导致的flip在i+K已经失效了
        return res
```




> 思路 2
******- 时间复杂度: O(N)******- 空间复杂度: O(1)******


我们也可以免去close列表的使用，取而代之的做法就是如果我们确实在i点flip了的话， 我们就将A[i]设置为-1，
然后在i+K点的时候，如果我们发现A[i]=-1的话，我们就知道i+K点要失去一次flip的效果

```python
class Solution:
    def minKBitFlips(self, A: 'List[int]', K: 'int') -> 'int':
        need = res = 0
        for i in range(len(A)):
            if i >= K and A[i - K] == -1:
                need -= 1
            if (need % 2) == A[i]:
                if i + K > len(A):
                    return -1
                A[i] = -1 # 代表i点flip过了
                need, res = need + 1, res + 1
        return res
```























