1769. 移动所有球到每个盒子所需的最小操作数

目录

题目:将所有小球移动到每个盒子的最少操作数

题目描述

题目示例

解题分析

解题方法

方法一:暴力计算

代码实现

复杂度分析

优化思路(可选)

示例说明

总结


题目:将所有小球移动到每个盒子的最少操作数

题目描述

给定一个长度为 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 位置的总操作数。

  • 移动操作的“代价”是小球从原来盒子到目标盒子之间的距离,距离为两盒子索引之差的绝对值。
  • 由于每步只能移动到相邻盒子,距离即为移动步骤数。
  • 多个小球的移动步数相加即可得到总步数。

解题方法

方法一:暴力计算

  1. 找出所有含有小球的盒子索引,存为列表 positions

对每个目标盒子 i,计算所有小球从其当前位置到 i 的距离总和,即:

  1. answer[i]=∑pos∈positions∣pos−i∣answer[i] = \sum_{pos \in positions} |pos - i|
  2. 返回答案数组。

这是一种直观易懂的方法。

代码实现

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),用于存储所有小球的位置。

优化思路(可选)

如果 nm 较大,这个解法会变慢。可以通过前缀和和差分技巧,将复杂度优化到 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],与示例一致。


总结

这道题主要考察对距离计算的理解和数组遍历。简单的暴力解法就能通过大部分测试,但可以用前缀和做进一步优化。

希望这篇博客帮你理清思路!如果你想了解前缀和优化版本,也可以告诉我,我来帮你写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值