leetcode 995. K 连续位的最小翻转次数
xxleyi opened this issue · comments
题:
在仅包含 0
和 1
的数组 A
中,一次 K
位翻转包括选择一个长度为 K
的(连续)子数组,同时将子数组中的每个 0
更改为 1
,而每个 1
更改为 0
。
返回所需的 K
位翻转的次数,以便数组没有值为 0
的元素。如果不可能,返回 -1
。
995. K 连续位的最小翻转次数 - 力扣(LeetCode)
解:
目标是将 0
翻转为 1
,翻转 0
的时候,有可能把 1
翻转为 0
,如果被多翻转了两次,1
又变回 1
。
所以我们有一个「循环不变量」相关的变量 flip
,类型是布尔值。针对第 i
个元素,如果 flip
为 false
,遇 0
翻转;反之,遇 1
翻转。
由于一次翻转涉及 k
个元素,所以隐约有个担忧: flip
的状态无法仅仅由 flip = !flip
这一个形式决定。我们仔细考察翻转能影响的范围 [i, i + k)
,在翻转 i
处元素时,i + k
处的元素不受当前 flip
状态的影响。所以当我们到了 i + k
处时,flip
需要额外进行一次翻转,以抵消掉 i
处的翻转。
所以,我们需要第二个「循环不变量」相关的变量 flipOneMore
,类型是数组,每一个元素初始值为 flase
, [0, k)
这个范围没有太大用处,且长度应该为 A.length + 1
const minKBitFlips = (A, K) => {
// initialize two loop invariants related variables: flip boolean and flipOneMore array
let flip = false, flipOneMore = Array(A.length + 1).fill(false)
// initialize count to save answer
let count = 0
for (let i = 0; i < A.length; i++) {
// update flip to ensure one loop invariant before loop
if (flipOneMore[i]) flip = !flip
if (+flip == A[i]) {
// check if cross border
if (i + K > A.length) return -1
// update count
// update flip and flipOneMore to ensure two loop invariants after loop
count += 1
flip = !flip
flipOneMore[i + K] = true
}
}
// if normal termination: count is our answer for A and K
return count
}