题目连接:
https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/
题目大意:
在仅包含 0 和 1 的数组 A 中,一次 K 位翻转包括选择一个长度为 K 的(连续)子数组,同时将子数组中的每个 0 更改为 1,而每个 1 更改为 0。
返回所需的 K 位翻转的次数,以便数组没有值为 0 的元素。如果不可能,返回 -1。
具体思路:
具体思路是贪心,就是从左边开始,碰到不符合的就直接进行翻转操作,最后检查一下整个数组是不是全为1的;然而这个样TLE了,最麻烦的时候复杂度可能会接近O(n*k)。
1 class Solution { 2 public: 3 int minKBitFlips(vector<int>& A, int K) { 4 int len = A.size(); 5 int ans = -1; 6 if(len == 0 )ans =- 1; 7 else { 8 int num = 0 , flag = 0; 9 for(int i = 0 ; i< len ;i++ ){ 10 if(A[i] == 0){flag=1;break;} 11 } 12 if(!flag)ans = -1; 13 else { 14 for(int i = 0; i <= len - K ;i++ ){ 15 if(A[i])continue; 16 num++; 17 for(int j = i ;j < i + K ; j++ ){ 18 A[j]^=1; 19 } 20 } 21 } 22 for(int i = 0 ; i< len ; i++ ){ 23 if(!A[i]){num=-1;break;} 24 } 25 ans=num; 26 } 27 return ans; 28 } 29 };
然后具体优化,我们其实可以把里面的长度为K的for循环给优化掉、这里可以运用差分的思想;每一次操作是在一个长度为K的区间进行的,所以当发现当前的位置0时,我们这个时候把这个点翻转一下,然后再把这个点往后k个点的位置标记一下,证明这个时候是需要再
翻转过来的(每一次标记相当于给这块区间翻转);然后具体判断是否需要翻转的时候,需要讨论一下情况;当当前位置翻转的次数为奇数的时候,这个点为1,也就是或翻转过后为偶数,这个时候是需要翻转的,也就是两个都为1 1。当当前位置翻转的次数为偶数的时候,这个点为0,这个时候也是需要翻转的;所以综合一下就是当 当前位置的翻转次数==当前位置时什么数 这个时候,是需要翻转的。
1 class Solution { 2 public: 3 int minKBitFlips(vector<int>&A, int K) { 4 int flag[30000+100]; 5 memset(flag,0,sizeof(flag)); 6 int tmp = 0 ;// tmp是记录当前位置的翻转次数的 7 int len = A.size(); 8 int num=0; 9 for( int i= 0; i<len ;i++){ 10 tmp^=flag[i]; 11 if(A[i] == tmp){ 12 num++; 13 if(i + K > len)return -1; 14 tmp^=1; 15 flag[i+K]^=1; 16 } 17 } 18 return num; 19 } 20 };