995. K 连续位的最小翻转次数
在仅包含 0
和 1
的数组 A
中,一次 K
位翻转包括选择一个长度为 K
的(连续)子数组,同时将子数组中的每个 0
更改为 1
,而每个 1
更改为 0
。
返回所需的 K
位翻转的最小次数,以便数组没有值为 0
的元素。如果不可能,返回 -1
。
示例 1:
输入:A = [0,1,0], K = 1 输出:2 解释:先翻转 A[0],然后翻转 A[2]。
示例 2:
输入:A = [1,1,0], K = 2 输出:-1 解释:无论我们怎样翻转大小为 2 的子数组,我们都不能使数组变为 [1,1,1]。
示例 3:
输入: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]
提示:
1 <= A.length <= 30000
1 <= K <= A.length
首先,对于每个位置,只有初始状态和反转总数确定最终状态。
另一方面,我们知道每个长度为K的间隔最多只能反转一次,因为两次反转对最终结果没有影响。
基于此,我们从前到后遍历数组。如果遇到0,我们将从当前位置开始反转长度为k的间隔。如果遇到0,剩余间隔的长度小于K,这表明我们无法完成反转。但是,如果每次我们反转当前间隔,反转间隔中的每个数字,时间复杂度为O(n * k),那么毫无疑问超时了。
因此我们需要进行优化,然后考虑每个位置上的元素,它只会受到前一个K-1元素是否反转的影响,因此我们只需要知道前一个k-1元素已经反转了多少次。 我们使用一个队列来存储在i之前的k-1位置反转了多少个元素(队列的长度指反转的次数)。 0反转偶数次为0,则需要反转; 1奇数次反转为0,也需要反转。只有0反转奇数次才变为1,而1反转偶数次为0不需要反转,如果最后k-1位置仍为0,则表示失败。否则,将i添加到队列中并更新答案。
class Solution { public: int minKBitFlips(vector<int>& A, int K) { int res=0,n=A.size(); queue<int> window;//window is used to store the index of the inverted element, the length of the window indicates the number of inversions for(int i=0;i<n;++i) { //When the distance between subscripts is greater than k, the team head subscript needs to be removed while(!window.empty()&&window.front() + K <= i) window.pop(); //The current position's 1 reversing odd times is 0 and needs to be reversed; the current position's 0 reversing even number of times is still 0 or still needs to be reversed if(A[i]==window.size()%2) { if(i+K>n)return -1; window.push(i); res++; } } return res; } };
相同的思想,另一种写法
class Solution { public: int minKBitFlips(vector<int>& A, int K) { int n=A.size(); int sum=std::accumulate(A.begin(), A.end(), 0); if(K==1)return n-sum; int res=0; int i=0; vector<bool>helper(n); bool running=false; while(i<n){ if(A[i]==0&&running==false||A[i]==1&&running==true){ if(i+K-1>=n)return -1; helper[i+K-1]=!helper[i+K-1]; running=!running; res++; } if(helper[i])running=!running; i++; } return res; } };
class Solution: def minKBitFlips(self, A: List[int], K: int) -> int: n=len(A) if K==1:return n-sum(A) res=0 i=0 helper=[False]*n running=False while i<n: if A[i]==0 and not running or A[i]==1 and running: if i+K-1>=n:return -1 res+=1 helper[i+K-1]=not helper[i+K-1] running=not running if helper[i]:running=not running i+=1 return res