在仅包含 0 和 1 的数组 A 中,一次 K 位翻转包括选择一个长度为 K 的(连续)子数组,同时将子数组中的每个 0 更改为 1,而每个 1 更改为 0。
返回所需的 K 位翻转的最小次数,以便数组没有值为 0 的元素。如果不可能,返回 -1。
例:
输入:A = [0,0,0,1,0,1,1,0], K = 3
输出:3
解释:
翻转 A[0],A[1],A[2]: A变成 [1,1,1,1,0,1,1,0]
翻转 A[4],A[5],A[6]: A变成 [1,1,1,1,1,0,0,0]
翻转 A[5],A[6],A[7]: A变成 [1,1,1,1,1,1,1,1]
题解:贪心算法+差分数组优化
要找到最小翻转次数,我们可以使用贪心算法的思想,遍历数组A,当遍历到的数字为0时,则以该数字为起点,翻转长度为K的子数组,若该子数组索引越界,则返回-1,若能遍历完数组A,则返回翻转的总次数。
class Solution {
public int minKBitFlips(int[] A, int K) {
int len=A.length;
int count=0;
for(int i=0;i<len;i++){
if(A[i]==0){
if(i+K-1>=len){
return -1;
}else{
for(int j=0;j<K;j++){
if(A[i+j]==0){
A[i+j]=1;
}else{
A[i+j]=0;
}
}
count++;
}
}
}
return count;
}
}
该算法的时间复杂度是O(NK),我们可以用差分数组对算法进行优化,使时间复杂度降为O(N)。
设第i个字符的翻转次数为 f[ i ](i=1,2,3…),设差分数组 int[ ] difference,difference[ 0 ]=f[ 0 ]=0,difference[ i ]=f[ i ]-f[ i-1 ](i!=0),则 f[ i ]=difference[ 0 ]+difference[ 1 ]+…+difference[ i ],当区间[ r , l ]内的所有数字都进行翻转时,只有difference[ r ]增大1与difference[ i+1 ]减小1,其余区间内的差分大小不变,这样极大简化了区间翻转时的算法操作,只需要变化difference[ r ]与difference[ i+1 ]即可。
class Solution {
public int minKBitFlips(int[] A, int K) {
int len=A.length;
int[]difference=new int[len+1];
int sum=0;
int ans=0;
for(int i=0;i<len;i++){
sum+=difference[i];
if((A[i]+sum)%2==0){
if(i+K>len){
return -1;
}
difference[i+1]++;
ans++;
difference[i+K]--;
}
}
return ans;
}
}