995. K 连续位的最小翻转次数

101 阅读2分钟

**题目: **
给定一个二进制数组 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
}