995. The minimum number of K continuous bit flips (sliding window + queue assist)

In array A containing only 0 and 1, a K bit flip involves selecting a (contiguous) sub-array of length K, and changing each 0 in the sub-array to 1 and changing each 1 to 0.

Returns the minimum number of K bit flips required so that the array has no elements with value 0. If it is not possible, return -1.

Example 1:

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

Input: A = [1,1,0], K = 2
Output: -1
Explanation: No matter how we flip the sub-array of size 2, we cannot make the array [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]

prompt:

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

analysis:

  • This question uses brute force to crack the timeout. After referring to other people's ideas, the problem is how to avoid the continuous reversal of the K values ​​after i in the inner loop in the brute force method.

  • Observing the problem, it is found that there are only two cases of 0 and 1 in the array A. The purpose is to set all to 1, then for 0, it must be flipped an odd number of times, and for 1 it must be flipped an even number of times to achieve the goal.而每一个当前元素要不要翻转,一方面要看自己是0还是1,另一方面要看该元素前面的元素翻转了多少次。

  • It can be seen from this that if we can have a data structure to record the element information that needs to be flipped, there is no need to repeat the 0->1,1->0 operation for the A[i] element. Here we use the queue advanced The first-out feature comes along with array A to traverse from left to right. The real-time length of the queue also reflects how many times the current element has been affected (flipped) by the flip window of the previous element. The code and comments are as follows:

class Solution {
    
    
public:
    int minKBitFlips(vector<int>& A, int K) {
    
    
        // 借助队列,其中的每一个元素的值表示从A中的哪个位置开始进行一次长度为K的翻转
        queue<int> q;
        int i = 0;
        int reverseTimes = 0;
        while(i < A.size()){
    
    
            // 遇到i >= q.front() + K,说明已经走完队列的第一个元素翻转影响的窗口
            // 队首出队,对于当前的i已经不受q.pop的影响了
            if(q.size() > 0 && i >= q.front() + K) q.pop();
            // 想象上来去找第一个需要翻转的0时,q.size与A[i]满足的数量关系
            // 对于遍历到的每一个元素,q.size()表示当前元素已经被翻转了q.size()次
            // 利用了对于0应该翻转奇数次,对于1应该翻转偶数次
            if(q.size() % 2 == A[i]){
    
    
                if(i + K > A.size()) return -1;
                q.push(i); // 存的是元素的下标,可以用来记录遍历到的位置
                ++reverseTimes;
            }
            ++i;
        }
        return reverseTimes;
    }
};

Insert picture description here

Guess you like

Origin blog.csdn.net/qq_34612223/article/details/113843907