【题解】力扣995. K 连续位的最小翻转次数

995. K 连续位的最小翻转次数

题目来源

995. K 连续位的最小翻转次数

思路

方法一、

差分思想

用差分思想来计算当前数字需要翻转的次数。开一个差分数组\(diff[A.length+1]\)来维护,多开1位,减少溢出判断

A的翻转次数为差分数组\(d[i]\)的累加和

image.png

当需要翻转时,只改变了\(diff[i]\)\(diff[i+k]\)的值。故\(diff[i]\)增加1,\(diff[i+k]\)减少1.

对于一个数若其经历了奇数次翻转,则其改变,若经历了偶数次翻转则其值未变,即

  • 0翻转偶数次后,数值仍然是0,需要被翻转
  • 0翻转奇数次后,数值变为1,无需被翻转
  • 1翻转偶数次后,数值任然是1,无需翻转
  • 1翻转奇数次后,数值变为0,需要被翻转
class Solution {
    public int minKBitFlips(int[] A, int K) {
        int len = A.length;
        int[] diff = new int[len+1];
        int ans = 0, revCnt = 0;
        for(int i = 0;i<len;i++){
            revCnt += diff[i];
            if((A[i]+revCnt) % 2 == 0){
                if(i + K > len){
                    return -1;
                }
                ans++;
                revCnt++;
                diff[i+K]--;
            }
        }
        return ans;
    }
}

方法二、

滑动窗口

使用队列来模拟滑动窗口,该滑动窗口的含义是前面\(K-1\)个元素中,以哪些位置其实的 子区间 进行了翻转。从左向右滑动,如果当前位置\(i\)需要翻转,则吧该位置存储到队列中。遍历到新位置\(j(j<i+K)\)时,队列中元素的个数代表了\(j\)被前面\(K-1\)个元素翻转的次数。

所以结论que.size() % 2 == A[i]时,当前元素需要翻转。

\(i+K>N\)时,说明需要翻转大小为\(K\) 的子区间,但是后面剩余的元素不到 \(K\)个了,所以返回 -1。

class Solution {
    public int minKBitFlips(int[] A, int K) {
        int res = 0;
        Deque<Integer> que = new LinkedList<>();
        for (int i = 0; i < A.length; i++) {
            if (que.size() > 0 && i > que.peek() + K - 1) {
                que.removeFirst();
            }
            //1.本来是1,翻转奇数次变为0,所以需要再次翻转,放入队列
            //2.本来是0,翻转偶数次还是0,所以需要再次翻转,放入队列
            if (que.size() % 2 == A[i]) {
                if (i + K > A.length) return -1;
                que.add(i);
                res += 1;
            }
        }
        return res;
    }
}

参考来源

  1. 官方题解.995K 连续位的最小翻转次数
  2. 负学明烛
  3. 三十三
posted @ 2021-03-08 18:25  zzzzzy2k  阅读(59)  评论(0编辑  收藏  举报