每日一题 LeetCode 21.02.18 java题解

nmd难死了

题目

https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/
每日一题 LeetCode 21.02.18 java题解_第1张图片
每日一题 LeetCode 21.02.18 java题解_第2张图片

差分数组

分析

考虑不去翻转数字,而是统计每个数字需要翻转的次数。对于一次翻转操作,相当于把子数组中所有数字的翻转次数加 11。
用差分数组的思想来计算当前数字需要翻转的次数。
维护一个差分数组diff[],其中diff[i]表示两个相邻元素A[i] A[i-1]反转次数之差。
对于区间 [l,r],将其元素全部加 1,只会影响到边界处的差分值,故 diff[i]加一,diff[r+1]减一。

通过累加差分数组可以得到当前位置需要翻转的次数,我们用变量 revCnt来表示这一累加值。
遍历到 A[i]时,若 A[i]+revCnt 是偶数,则说明当前元素的实际值为0,需要翻转区间 [i,i+K-1][i,i+K−1],我们可以直接将 revCnt 增加1,diff[i+K] 减少1。

复杂度

时间复杂度:O(N),其中 N 是数组 A 的长度。需要对数组 A 遍历一次。
空间复杂度:O(N),其中 N 是数组 A 的长度。需要创建一个长度为N+1 的差分数组 diff

代码

class Solution {
    public int minKBitFlips(int[] A, int K) {
        int len=A.length;
        int[] diff=new int[len+1];
        int res=0;//总翻转次数
        int revCnt=0;//当前位置需要翻转次数
        for(int i=0;i<len;i++){
            revCnt=revCnt+diff[i];
            //第i个元素的实际值,为A[i]加上翻转次数
            if((A[i]+revCnt)%2==0){//当前元素的实际值为0
                //无法翻转
                if(i+K-1>len-1){
                    return -1;
                }
                //进行翻转
                res++;
                revCnt++;
                diff[i+K]--;//翻转的最后一个位置是i+K-1,它的后一个位置跟它的 差-1
            }
        }
        return res;
    }
}

滑动窗口

分析

当遍历到位置 i 时,若能知道位置 i-K上发生了翻转操作,便可以直接修改 revCnt,从而去掉 diff 数组。
我们可以用 A[i]范围之外的数来表达「是否翻转过」的含义。
具体来说,若要翻转从位置 i 开始的子数组,可以将 A[i]加 2,这样当遍历到位置 i‘时,若有 A[i’-K]>1,则说明在位置 i’-K 上发生了翻转操作。

复杂度

时间O(n)
空间O(1)

代码

class Solution {
    public int minKBitFlips(int[] A, int K) {
        int len=A.length;
        int[] diff=new int[len+1];
        int res=0;//总翻转次数
        int revCnt=0;//当前位置需要翻转次数
        for(int i=0;i<len;i++){
            if(i-K>=0&&A[i-K]>1){
                revCnt=revCnt^1;
            }
            //反转奇数次后是1 或者 反转偶数次后是0
            if(A[i]==revCnt){//当前元素的实际值为0
                //无法翻转
                if(i+K-1>len-1){
                    return -1;
                }
                //进行翻转
                res++;
                revCnt=revCnt^1;
                A[i]=A[i]+2;//以i开头的窗口,翻转过
            }
        }
        return res;
    }
}
//---------------
class Solution {
    public int minKBitFlips(int[] A, int K) {
        int len=A.length;
        int[] diff=new int[len+1];
        int res=0;//总翻转次数
        int revCnt=0;//当前位置需要翻转次数
        for(int i=0;i<len;i++){
            if(i-K>=0&&A[i-K]>1){
                revCnt=revCnt+1;
            }
            //第i个元素的实际值,为A[i]加上翻转次数
            
            if((A[i]+revCnt)%2==0){//当前元素的实际值为0
                //无法翻转
                if(i+K-1>len-1){
                    return -1;
                }
                //进行翻转
                res++;
                revCnt++;
                A[i]=A[i]+2;//以i开头的窗口,翻转过
            }
        }
        return res;
    }
}

直接模拟-超时

class Solution {
    public int minKBitFlips(int[] A, int K) {
        int len=A.length;
        int i=0;
        int j=K-1;
        int count=0;
        while(i<=len-K){
            if(A[i]==1){
                i++;
                j++;
                continue;
            }
            else{
                reverse(A,i,j);
                count++;
                i++;
                j++;
            }
        }
        for(int o=len-K+1;o<len;o++){
            if(A[o]==0)
                return -1;
        }
        return count;
    }
    public static void reverse(int[] A,int i,int j){
        for(int k=i;k<=j;k++){
            if(A[k]==0)
                A[k]=1;
            else
                A[k]=0;
        }
    }
}

你可能感兴趣的:(LeetCode,数据结构,java,算法,leetcode)