995. K 连续位的最小翻转次数
贪心+模拟
初步的想法,从头开始遍历,A[i]碰到0就需要翻转一下从i开始的长度为K的子数组,于是模拟下反转的过程。
class Solution {
int[] A;
int K, n, res;
public int minKBitFlips(int[] A, int K) {
this.A = A;
this.K = K;
this.n = A.length;
for(int i = 0; i < n - K; i++)
if(A[i] == 0) flip(i);
int sum = 0;
for(int i = n - K; i < n; i++) sum += A[i];
return sum == 0 ? res + 1 : (sum == K ? res : -1);
}
void flip(int index){
res++;
for(int i = index; i < index + K; i++) A[i] = 1 - A[i];
}
}
时间复杂度 O ( N K ) O(NK) O(NK)超时
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y3XiUJgn-1613617074276)(https://pic.leetcode-cn.com/1613616642-FAjsMW-image.png)]
贪心+计算是否翻转
使用一个变量
f
l
i
p
flip
flip来表示当前的翻转次数,若为偶数则相当于不变,奇数相当于翻转。这里利用了模2加法相当于异或的操作,是否翻转,1表示翻转,0表示不变。
那么,每次碰到0就需要把flip翻转一下,表示后续的数字需要翻转,但是需要保证到K的时候就不需要这次翻转了,因此需要记录一下:通过将A[i] += 2来表示从i开始到i+K的数组需要翻转,这样的话,就可以遍历到i时,先判断一下A[i - K]是否大于1,若大于1表示这个位置之前翻转过,需要取消之前的影响,把flip翻转一下。
class Solution {
public int minKBitFlips(int[] A, int K) {
int n = A.length, res = 0, flip = 0;
for(int i = 0; i < n; i++){
if(i >= K && A[i - K] > 1) flip ^= 1; //模2加法相当于异或
if((A[i] ^ flip) == 0){
if(i + K > n) return -1;
flip ^= 1;
res++;
A[i] += 2;
}
}
return res;
}
}
时间复杂度
遍历一遍 O ( N ) O(N) O(N)
空间复杂度
使用常数级别额外空间 O ( 1 ) O(1) O(1)