nmd难死了
题目
https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/
差分数组
分析
考虑不去翻转数字,而是统计每个数字需要翻转的次数。对于一次翻转操作,相当于把子数组中所有数字的翻转次数加 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;
}
}
}