LeetCode 题解工作台
拾起 K 个 1 需要的最少行动次数
给你一个下标从 0 开始的二进制数组 nums ,其长度为 n ;另给你一个 正整数 k 以及一个 非负整数 maxChanges 。 Alice 在玩一个游戏,游戏的目标是让 Alice 使用 最少 数量的 行动 次数从 nums 中拾起 k 个 1 。游戏开始时,Alice 可以选择数组 [0,…
4
题型
5
代码语言
3
相关题
当前训练重点
困难 · 滑动窗口(状态滚动更新)
答案摘要
我们考虑枚举 Alice 的站立位置 ,对于每个 ,我们按照如下的策略进行操作: - 首先,如果位置 的数字为 ,我们可以直接拾取一个 ,不需要行动次数。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 滑动窗口(状态滚动更新) 题型思路
题目描述
给你一个下标从 0 开始的二进制数组 nums,其长度为 n ;另给你一个 正整数 k 以及一个 非负整数 maxChanges 。
Alice 在玩一个游戏,游戏的目标是让 Alice 使用 最少 数量的 行动 次数从 nums 中拾起 k 个 1 。游戏开始时,Alice 可以选择数组 [0, n - 1] 范围内的任何索引 aliceIndex 站立。如果 nums[aliceIndex] == 1 ,Alice 会拾起一个 1 ,并且 nums[aliceIndex] 变成0(这 不算 作一次行动)。之后,Alice 可以执行 任意数量 的 行动(包括零次),在每次行动中 Alice 必须 恰好 执行以下动作之一:
- 选择任意一个下标
j != aliceIndex且满足nums[j] == 0,然后将nums[j]设置为1。这个动作最多可以执行maxChanges次。 - 选择任意两个相邻的下标
x和y(|x - y| == 1)且满足nums[x] == 1,nums[y] == 0,然后交换它们的值(将nums[y] = 1和nums[x] = 0)。如果y == aliceIndex,在这次行动后 Alice 拾起一个 1 ,并且nums[y]变成0。
返回 Alice 拾起 恰好 k 个 1 所需的 最少 行动次数。
示例 1:
输入:nums = [1,1,0,0,0,1,1,0,0,1], k = 3, maxChanges = 1
输出:3
解释:如果游戏开始时 Alice 在 aliceIndex == 1 的位置上,按照以下步骤执行每个动作,他可以利用 3 次行动拾取 3 个 1 :
- 游戏开始时 Alice 拾取了一个 1 ,
nums[1]变成了0。此时nums变为[1,0,0,0,0,1,1,0,0,1]。 - 选择
j == 2并执行第一种类型的动作。nums变为[1,0,1,0,0,1,1,0,0,1] - 选择
x == 2和y == 1,并执行第二种类型的动作。nums变为[1,1,0,0,0,1,1,0,0,1]。由于y == aliceIndex,Alice 拾取了一个 1 ,nums变为[1,0,0,0,0,1,1,0,0,1]。 - 选择
x == 0和y == 1,并执行第二种类型的动作。nums变为[0,1,0,0,0,1,1,0,0,1]。由于y == aliceIndex,Alice 拾取了一个 1 ,nums变为[0,0,0,0,0,1,1,0,0,1]。
请注意,Alice 也可能执行其他的 3 次行动序列达成拾取 3 个 1 。
示例 2:
输入:nums = [0,0,0,0], k = 2, maxChanges = 3
输出:4
解释:如果游戏开始时 Alice 在 aliceIndex == 0 的位置上,按照以下步骤执行每个动作,他可以利用 4 次行动拾取 2 个 1 :
- 选择
j == 1并执行第一种类型的动作。nums变为[0,1,0,0]。 - 选择
x == 1和y == 0,并执行第二种类型的动作。nums变为[1,0,0,0]。由于y == aliceIndex,Alice 拾起了一个 1 ,nums变为[0,0,0,0]。 - 再次选择
j == 1并执行第一种类型的动作。nums变为[0,1,0,0]。 - 再次选择
x == 1和y == 0,并执行第二种类型的动作。nums变为[1,0,0,0]。由于y == aliceIndex,Alice 拾起了一个 1 ,nums变为[0,0,0,0]。
提示:
2 <= n <= 1050 <= nums[i] <= 11 <= k <= 1050 <= maxChanges <= 105maxChanges + sum(nums) >= k
解题思路
方法一:贪心 + 前缀和 + 二分查找
我们考虑枚举 Alice 的站立位置 ,对于每个 ,我们按照如下的策略进行操作:
- 首先,如果位置 的数字为 ,我们可以直接拾取一个 ,不需要行动次数。
- 然后,我们对 的左右两侧位置的数字 进行拾取,执行的是行动 ,即把位置 的 移到位置 ,然后拾取;把位置 的 移到位置 ,然后拾取。每拾取一个 ,需要 次行动。
- 接下来,我们最大限度地将 或 上的 ,利用行动 ,将其置为 ,然后利用行动 ,将其移动到位置 ,拾取。直到拾取的 的数量达到 或者行动 的次数达到 。我们假设行动 的次数为 ,那么总共需要 次行动。
- 利用完行动 ,如果拾取的 的数量还没有达到 ,我们需要继续考虑在 和 的区间内,进行行动 ,将 移动到位置 ,拾取。我们可以使用二分查找来确定这个区间的大小,使得拾取的 的数量达到 。具体地,我们二分枚举一个区间的大小 ,然后在区间 和 内,进行行动 ,将 移动到位置 ,拾取。如果拾取的 的数量达到 ,我们就更新答案。
时间复杂度 ,空间复杂度 。其中 是数组 的长度。
class Solution:
def minimumMoves(self, nums: List[int], k: int, maxChanges: int) -> int:
n = len(nums)
cnt = [0] * (n + 1)
s = [0] * (n + 1)
for i, x in enumerate(nums, 1):
cnt[i] = cnt[i - 1] + x
s[i] = s[i - 1] + i * x
ans = inf
max = lambda x, y: x if x > y else y
min = lambda x, y: x if x < y else y
for i, x in enumerate(nums, 1):
t = 0
need = k - x
for j in (i - 1, i + 1):
if need > 0 and 1 <= j <= n and nums[j - 1] == 1:
need -= 1
t += 1
c = min(need, maxChanges)
need -= c
t += c * 2
if need <= 0:
ans = min(ans, t)
continue
l, r = 2, max(i - 1, n - i)
while l <= r:
mid = (l + r) >> 1
l1, r1 = max(1, i - mid), max(0, i - 2)
l2, r2 = min(n + 1, i + 2), min(n, i + mid)
c1 = cnt[r1] - cnt[l1 - 1]
c2 = cnt[r2] - cnt[l2 - 1]
if c1 + c2 >= need:
t1 = c1 * i - (s[r1] - s[l1 - 1])
t2 = s[r2] - s[l2 - 1] - c2 * i
ans = min(ans, t + t1 + t2)
r = mid - 1
else:
l = mid + 1
return ans
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | Depends on the final approach |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
The candidate efficiently manages the sliding window with updates to the running state.
- question_mark
The candidate makes use of greedy techniques while keeping track of the number of moves.
- question_mark
The candidate balances between the cost of making changes and moving within the window.
常见陷阱
外企场景- error
Failing to update the state of the window correctly when sliding, especially when zeros are converted.
- error
Not accounting for the cost of changing zeros into ones, which requires 2 moves per change.
- error
Inefficiently recalculating subarrays or prefix sums, leading to higher time complexity.
进阶变体
外企场景- arrow_right_alt
Handling different values for k and maxChanges can lead to variations in the optimal solution and performance.
- arrow_right_alt
Consider arrays with no zeros (all ones) or no ones (all zeros) for edge cases.
- arrow_right_alt
Experimenting with larger arrays may require optimizations like prefix sum usage to avoid time limit exceeded errors.