📌  相关文章
📜  要翻转的 0 计数以使任何两个相邻的 1 至少相隔 K 个 0(1)

📅  最后修改于: 2023-12-03 15:41:33.623000             🧑  作者: Mango

翻转 0 计数以满足相邻 1 之间至少有 K 个 0

问题描述

给定一个二进制数组和一个整数 K,您需要翻转一些 0 以使得每两个相邻的 1 之间至少有 K 个 0,并输出最少需要翻转的 0 的数量。如果无法满足要求,返回 -1。

输入
  • nums:二进制数组,[0,1]组成的数组,长度不超过 $10^5$
  • K:整数,大于等于1
输出
  • res:最少需要翻转的 0 的数量,如果无法满足要求,返回 -1。
示例
输入: nums = [1,0,0,1,1,1], k = 2
输出: 1
解释: 翻转第二个 0,数组变为 [1,0,1,1,0,1],每两个相邻的 1 之间至少有 2 个 0。

输入: nums = [1,0,0,1,1,1], k = 3
输出: -1
解释: 无法满足要求。
说明
  • 0 <= nums.length <= 10^5
  • 0 <= k <= nums.length
思路

在初始时,我们找到第一个 1 出现时的下标,将其记录为 lastOne。如果找不到 1,说明数组中没有 1,不需要翻转,直接返回 0。如果数组中仅有一个 1,也不需要翻转,直接返回 0。

接下来,我们维护一个变量 cnt 来记录每次翻转 0 的数量,以及一个变量 lastZero 来记录上一次翻转的 0 的下标。在遍历数组时,如果当前位置为 0,我们判断上一次翻转的 0 距当前位置的距离是否小于 K,如果小于 K,则无法满足要求,返回 -1。

如果距离大于等于 K,则当前位置的 0 可以翻转。我们将 cnt 加一,并将当前位置的下标记录为 lastZero。如果当前位置为 1,则判断 lastOne 是否为 -1。如果 lastOne 为 -1,则说明当前位置是数组中的第一个 1,直接将 lastZero 赋值给 lastOne;否则,判断上一次翻转的 0 距离上一个 1 的距离是否小于 K,如果小于 K,则还需要继续翻转 0,我们将 lastZero 变为上一个 1 的下标并将 cnt 加一,否则直接将 lastZero 赋值给 lastOne。

最后,我们再次判断上一次翻转的 0 距最后一个 1 的距离是否小于 K,如果小于 K,则无法满足要求,返回 -1。否则,返回 cnt。

代码实现
class Solution:
    def minKBitFlips(self, nums: List[int], k: int) -> int:
        n = len(nums)
        cnt, lastOne, lastZero = 0, -1, -1
        for i in range(n):
            if nums[i] == 0:
                if i - lastZero < k:
                    return -1
                cnt += 1
                lastZero = i
            else:
                if lastOne == -1:
                    lastOne = lastZero
                elif i - lastOne < k:
                    if lastZero == lastOne:
                        return -1
                    cnt += 1
                    lastZero = lastOne
                lastOne = i
        if n - lastOne <= k:
            return cnt
        return -1

代码解释见注释部分。