目录
题目:将所有小球移动到每个盒子的最少操作数
题目描述
给定一个长度为 n
的二进制字符串 boxes
,其中:
boxes[i] = '0'
表示第i
个盒子是空的,boxes[i] = '1'
表示第i
个盒子里有一个小球。
你可以进行如下操作:
- 每一步可以将一个小球从某个盒子移动到与之相邻的盒子中(相邻定义为索引差绝对值为 1)。
注意,操作后盒子中可以存在多个小球堆叠。
要求返回一个长度为 n
的数组 answer
,其中 answer[i]
表示将所有小球移动到第 i
个盒子所需的最少操作数。
题目示例
示例 1:
输入:boxes = "110"
输出:[1,1,3]
解释:
- 将所有小球移到第 0 个盒子时:
从第 1 个盒子移动 1 步,总共 1 步。
- 将所有小球移到第 1 个盒子时:
从第 0 个盒子移动 1 步,总共 1 步。
- 将所有小球移到第 2 个盒子时:
第 0 盒子小球移动 2 步,
第 1 盒子小球移动 1 步,
共计 3 步。
示例 2:
输入:boxes = "001011"
输出:[11,8,5,4,3,4]
解题分析
对于每个盒子 i
,我们需要计算将所有小球移动到盒子 i
位置的总操作数。
- 移动操作的“代价”是小球从原来盒子到目标盒子之间的距离,距离为两盒子索引之差的绝对值。
- 由于每步只能移动到相邻盒子,距离即为移动步骤数。
- 多个小球的移动步数相加即可得到总步数。
解题方法
方法一:暴力计算
- 找出所有含有小球的盒子索引,存为列表
positions
。
对每个目标盒子 i
,计算所有小球从其当前位置到 i
的距离总和,即:
- answer[i]=∑pos∈positions∣pos−i∣answer[i] = \sum_{pos \in positions} |pos - i|
- 返回答案数组。
这是一种直观易懂的方法。
代码实现
from typing import List
class Solution:
def minOperations(self, boxes: str) -> List[int]:
n = len(boxes)
positions = [i for i, ch in enumerate(boxes) if ch == '1']
answer = []
for i in range(n):
total_moves = 0
for pos in positions:
total_moves += abs(pos - i)
answer.append(total_moves)
return answer
复杂度分析
- 时间复杂度:
O(n * m)
,其中n
是盒子数,m
是小球数。
对于每个盒子,我们都遍历所有小球位置计算距离。 - 空间复杂度:
O(m)
,用于存储所有小球的位置。
优化思路(可选)
如果 n
和 m
较大,这个解法会变慢。可以通过前缀和和差分技巧,将复杂度优化到 O(n)
。
简要思路:
- 先统计所有小球的个数和位置的和。
- 使用前缀和维护当前左边和右边小球的数量和距离代价。
- 递推计算下一个盒子所需的操作数。
但这种实现较复杂,需要较强的算法基础,这里暂不展开。
示例说明
以 boxes = "110"
为例:
- 小球位置
positions = [0, 1]
计算每个盒子:
- 盒子 0:
|0-0| + |1-0| = 0 + 1 = 1
- 盒子 1:
|0-1| + |1-1| = 1 + 0 = 1
- 盒子 2:
|0-2| + |1-2| = 2 + 1 = 3
最终返回 [1, 1, 3]
,与示例一致。
总结
这道题主要考察对距离计算的理解和数组遍历。简单的暴力解法就能通过大部分测试,但可以用前缀和做进一步优化。
希望这篇博客帮你理清思路!如果你想了解前缀和优化版本,也可以告诉我,我来帮你写。