**题目: **
给定一个二进制数组 nums 和一个整数 k 。
k位翻转 就是从 nums 中选择一个长度为 k 的 子数组 ,同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 都改成 0 。
返回数组中不存在 0 所需的最小 k位翻转 次数。如果不可能,则返回 -1 。
子数组 是数组的 连续 部分。
算法:
方法一:差分数组
思路:考虑nums每一个元素翻转次数,如果nums[i] = 0我们才以i作为子数组的开始,进行翻转。
如果nums[i] = 0,翻转奇数次最后为1
如果nums[i] = 1,翻转偶数次最后为1。
我们每次翻转k位长度的子数组,则这k个子数组每个元素的翻转次数加1,最后求nums每一个元素的翻转次数。如果i + K > n,还在进行翻转,则说明无法做到。
func minKBitFlips(nums []int, k int) int {
diff := make([]int, len(nums) + 1)
curRevCount := 0
totalRevCount := 0
for i := range nums {
// 当前这个数字的翻转次数
curRevCount = curRevCount + diff[i]
// nums[i] == 0 翻转了偶数次
// nums[i] == 1 翻转了奇数次,则需要再进行翻转
if (nums[i] == 0 && curRevCount % 2 == 0) || (nums[i] == 1 && curRevCount % 2 != 0) {
if i + k > len(nums) {
return - 1
}
// diff[i] = diff[i] + 1
curRevCount ++
diff[i + k] = diff[i + k] - 1
totalRevCount ++
}
}
return totalRevCount
}
方法二:滑动窗口
func minKBitFlips(nums []int, k int) int {
curRevCount := 0
totalRevCount := 0
for i := range nums {
// 当前这个数字的翻转次数
if i >= k && nums[i - k] > 1 {
curRevCount = curRevCount ^ 1
nums[i - k] = nums[i - k] - 2
}
// nums[i] == 0 翻转了奇数次
// nums[i] == 1 翻转了偶数次,则需要再进行翻转
if (nums[i] == 0 && curRevCount % 2 == 0) || (nums[i] == 1 && curRevCount % 2 != 0) {
if i + k > len(nums) {
return - 1
}
curRevCount = curRevCount ^ 1
totalRevCount ++
nums[i] = nums[i] + 2
}
}
return totalRevCount
}