• 995. Minimum Number of K Consecutive Bit Flips (2021/2/18每日一题)


    995. 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

    题目大意:题目要求将窗口K内的所有数字反转,0变1,1变0,最后要求整个数组不存在0,问最低反转多少次。

    思路:看到题时一直在想:最低反转多少次?用dp?好像怎么也推不出转移公式,因为前面有0就必须反转,不存在需不需要反转的问题。用greedy? 看了下标签果然,贪心+滑动窗口。

    基本思路是:遇到0即反转以当前位置起始的窗口K内的所有位置,但如果每次都修改数组里的值,时间复杂度会变为K*N,那有没有办法将时间复杂度降为N呢?答案是有!用变量cur记录当前位曾反转的次数,可以得出结论,只有前面K-1个位置会影响当前位置的反转次数,因此用cur记录前面K-1个位置的反转次数和。是不是很耳熟?窗口加和啊,后面加一个前面减一个啊,减神马呢?用一个与输入等长的数组flip记录每位数字是否需要反转,用变量res记录最终反转多少次。

    用例子来说明:[0,0,0,1,0,1,1,0], K=3

    注:每次计算i位时,为以i为起始长度为K的窗口,图中标黄色的长度为K的窗口为对当前位有反转影响的窗口(比如看一个数组前四位,A = [A[0], A[1], A[2], A[3]....], k=3. 看 A[3]的位置。A[3]的位置只跟A[1], A[2]有关系,如果A[1]要反,肯定要反1,2,3,如果A[2]要反,肯定要反2,3,4。但如果A[0]反,就只反0,1,2,对A[3]没有影响)。比如第五步判断i=3时,计算窗口i=3,4,5位是否需要被反转, 而对3,4,5位是否需要被反转结果有影响的窗口为第五步图中标黄的窗口i=1,2,3.

    第一步:初始化 cur = 0, res = 0, flip = 0

    第二步:判断i=0时,此时cur为初始值0,并且i <K未达到窗口长度,因此cur即为当前数字曾经反转的次数,cur % 2 == 0(即相当于未曾被反转过)。A[0] = 0,题目要求不存在0,因此i=0位需要被反转。

    更新cur = 1, res = 1, flip[0] = 1;此时窗口长度为1.

     第三步:判断i=1时,此时cur = 1, i<K未达到窗口长度,cur为当前数字曾经反转的次数,cur % 2 = 1(即当前数字已被反转过,而且未被反转回来,即1->0, 0->1),A[1] = 0,因此此时 i=1位已经被反转为1,不需要再进行操作。当前窗口长度为2.

     第四步:与第三步同,窗口长度为3==K

     第五步:判断i=3时,当前cur=1, 因为滑到i=3时窗口长度为4>K,第i-K=0位的反转不会影响到i=3的位置,只有i =1,2位的反转操作窗口包含了i=3位。因此cur需要减掉对第i-K位的反转次数才能得到当前位曾经被反转的次数。因此cur = cur -flip[i-K] = 1-1=0. 即i=3位未被反转过(it make sense, 因为以i=1, i=2位起始的窗口都未作反转操作)。但A[3] = 1已经是1了,因此还是不需要进行操作,只需要更新cur值:

     第六步:判断i=4时,cur = 0, cur = cur-flip[i-K] = 0-0=0, 当前值未被反转过,且A[4] = 0,因此需要进行反转操作,更新cur = cur+1=1, res = res+1=2, flip[4] = 1:

     第七步:判断i=5时,cur = 1, cur = cur - flip[i-K] =1-0=1,  cur % 2 = 1即当前值已经被反转(0->1, 1->0),且A[5] = 1, 说明A[5]经过前面的反转已经变为0了,因此需要再次被反转成为1.

    更新cur = cur+1=2, res = res+1=3, flip[5] = 1: 

    注:因为此时i+K = A.size(),因此以i=5起始的窗口为最后一个窗口,其后的窗口都小于K. 因此也是反转操作的最后一个窗口。

     第七步:判断i=6, cur = 2, cur = cur-flip[i-K] = 2-0=2, cur % 2 = 0,即当前值虽然曾经被反转过,但反转过偶数次,即经过前面窗口内值的反转后值不变。A[6] = 1:

    注:因为i +K=6+3 >A.size(),因此此位不管是0是1都不能进行反转操作,为1即可向后判断,为0则直接返回-1.

     第八步:判断i=7, cur = 2, cur = cur-flip[i-K] = 2-1 = 1, cur % 2 = 1,  即当前值已被反转为不同的值(0->1, 1->0), A[7] = 0,经反转后变为1

    第九步:返回res值。代码如下:

     1 class Solution {
     2 public:
     3     int minKBitFlips(vector<int>& A, int K) {
     4         int res = 0, cur = 0;
     5         vector<int> flip(A.size(), 0);
     6         for(int i=0; i<A.size(); i++){
     7             if(i >= K) cur -= flip[i-K];
     8             if((A[i] == 0 && cur % 2 == 0) ||
     9                 (A[i] == 1 && cur % 2 == 1)){
    10                     if(i > A.size()-K){
    11                         return -1;
    12                     } else {
    13                         res++;
    14                         cur++;
    15                         flip[i] = 1;
    16                     }
    17                 }
    18         }
    19         return res;
    20     }
    21 };

    画图太痛苦了~画的我想吐血

  • 相关阅读:
    kong插件Prometheus+grafana图形化展示
    FTP服务—三种登录类型的配置方法
    [Kong] basic-auth基本认证及ACL鉴权
    centos7 U盘安装及Raid划分的完整流程
    [Kong] key-auth实现对API请求的密钥认证
    修改gitlab默认的nginx
    gitlab配置邮箱服务
    gitlab部署及汉化
    kong配置upstream实现简单的负载均衡
    mybaties只能驼峰映射,怎么可能,虐渣渣。(springboot)
  • 原文地址:https://www.cnblogs.com/boligongzhu/p/14416548.html
Copyright © 2020-2023  润新知