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

小夏 教育 更新 2024-02-12

在仅包含 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,1,1,0,0,0]。

翻转 a[5],a[6],a[7]:a 变为 [1,1,1,1,1,1,1,1,1]。

提示:

1 <= a.length <= 30000

1 <= k <= a.length

连续子阵列优化首先考虑暴力破解。 蛮力的想法可以从左到右遍历数组,如果我们击中零,我们将其向左翻转。 翻转的长度自然是一个子数组,其起始长度为 k。 原样用它作为左端翻转它,所以如果我们遇到一个 0,我们必须执行翻转,否则我们无法获得完整的 1 数组。 由于翻转的顺序不会影响最终结果,即如果最终答案是翻转以 i、j、k 开头的子数组,那么谁先翻转然后翻转,谁就是一样的。 因此,可以从左到右遍历。

总结一下:蛮力的思路可以是从左到右遍历数组,如果我们打到一个0,我们把它翻转到左边,在当前位置的开头修改长度为k的子数组,同时计数器+1,如果数组不全是0,最后返回-1, 否则返回计数器的值。

语言支持:python3python3 代码:

class solution: def minkbitflips(self, a, k): n = len(a) ans = 0 for i in range(n - k + 1): if a[i] == 1: continue for j in range(k): a[i + j] ^= 1 ans += 1 for i in range(n): if a[i] == 0: return -1 return ans
复杂性分析

设 n 为数组的长度。

时间复杂度:$o(n * k)$Space复杂度:$o(1)$For这种连续子阵列的问题。 一般来说,只有几个优化思路。 让我们列举一下:

前缀和 & 差异分数组滑动窗口双端队列。 例如,1696跳跃游戏 vi 和 239Sliding Window Max 是一种思维方式。 我已经写过这三种技术,所以如果你不了解它们,你可以先看看它们。

对于这个问题,我们可以使用差异组或双端队列进行优化。 无论采用哪一种,基本思想都是相似的,也可以对比下面的**,看看他们思想的一致性。 简单来说,他们的思维是相似的,区别只是用于解决问题的数据结构不同,因此API不同。 因此,我不认为这两者是两种解决方案。

对于差分组,在上述蛮力解的内层中有一个 k 的循环。 另一方面,如果仅使用差分组修改端点的值,则可以轻松地将时间复杂度优化为 $o(n)$。

对于双端队列,如果需要翻转当前位置,则将其排队。 那么,你怎么知道你当前位置的数字是多少呢? (可能是由于前一位数字的翻转,当前位置。翻了几次,可能不是以前的数字)。由于偶数次翻转等于不翻转,奇数次翻转效果相同,因此只需要记录翻转的奇偶校验。 这实际上是队列长度的奇偶校验。 因为队列的长度是当前号码被翻转的次数。当然,这需要您从队列中删除那些已经超过 k 的。

连续子阵列优化技巧 语言支持: python3python3 代码:

差异分数组:

class solution: def minkbitflips(self, a: list[int], k: int) -int: n = len(a) diff = [0] *n + 1) ans, cur = 0, 0 for i in range(n): cur += diff[i] if cur % 2 == a[i]: if i + k > n: return -1 ans += 1 cur += 1 diff[i + k] -= 1 return ans
复杂性分析

设 n 为数组的长度。

时间复杂度:$o(n)$Spatial复杂度:$o(n)$double结束队列:

class solution: def minkbitflips(self, a, k): n = len(a) q = collections.deque() ans = 0 for i in range(n): if q and i >= q[0] +k: q.popleft() if len(q) %2 == a[i]: if i + k > n: return -1 q.append(i) ans += 1 return ans
复杂性分析

设 n 为数组的长度。

时间复杂度:$o(n)$Spatial复杂度:$o(k)$Regardless 不管是使用差分组还是双端队列,都不需要使用额外的数据结构,而是使用原来的数组 a,即原位修改

例如,我们只能记录双端队列的长度,并且要确定队列中是否有一个数字,我们只需要将其映射到问题数据范围内的另一个数字即可。 由于问题数据范围为 [0,1],我们可以将其映射到 2。

原位修改语言支持:python3python3 代码:

class solution: def minkbitflips(self, a, k): flips = ans = 0 for i in range(len(a)):if i >= k and a[i - k] -2 == 0: flips -= 1 if (flips % 2) == a[i]: if i + k > len(a): return -1 a[i] = 2 flips += 1 ans += 1 return ans
复杂性分析

设 n 为数组的长度。

时间复杂度:$o(n)$Space复杂度:$o(1)$

相似文章

    LeetCode 数组和矩阵

    给定数组 a ,,n 请构造一个数组 b ,,n 其中元素 b i a a a i a i a n 不能使用除法。注 b a a a n b n a a a n 想法 假设 left i a a i right i a i a n 所以 b i left i right i 可以知道 left i ...

    LeetCode 堆栈和队列

    剑指 字符流中的第一个不同字符是指 堆叠压入,顶出顺序 使用堆栈实现队列 使用队列实现堆栈 最小堆栈 实现了与堆栈的支架匹配数组中的元素 递减堆栈 与大于它的下一个元素之间的距离 每日温度 循环数组中大于当前元素的下一个元素指向 滑动窗口的最大值为 删除字符串中所有相邻的重复项简化路径 Catch ...

    Leetcode 2009 使数组具有最少的操作数

    给你一个整数 nums 数组。在每个操作中,您都可以将 nums 中的任何元素替换为任意整数。如果 Nums 满足以下条件,则它是连续的 nums 中的所有元素彼此不同。nums 中最大元素和最小元素之间的差值等于 numslength 例如,nums ,,, 是连续的,但 nums ,,,, 不是...

    Leetcode 1671 获取山阵列的最小删除次数

    当且仅当 arr 满足以下条件时,我们将 arr 定义为山峰阵列 arr.length 有一个下标 i 从 开始 满足 i arr长度 和 arr arr i arr i arr arr.length 给定一个整数数组 nums,请返回将 nums 删除到山形数组中的最小次数。示例 输入 nums ...

    Leetcode 1723 完成所有工作的最短时间

    为您提供一个整数作业数组,其中 jobs i 是完成第 i 个作业所需的时间。要求您将这些作业分配给 k 个工作线程。所有作业都应分配给工作人员,并且每个作业只能分配给一个工作人员。工人的工作时间是完成分配给他们的所有工作所花费的时间的总和。请设计一个最佳的工作分配计划,以尽量减少工人的最长工作时间...