巧克力板选择问题 | 豆包MarsCode AI刷题

129 阅读4分钟

1. 问题分析

给定 n 块巧克力板,每块巧克力的边长是数组 a[i],并且每块巧克力的重量是其边长的平方,即 a[i]^2。小M有多个背包,每个背包有不同的最大承重限制,题目要求我们计算每个背包能装入的最多巧克力块数。

2. 解决思路

这个问题本质上是一个 背包问题,但和传统的背包问题不同,每个背包的最大承重是不同的。我们可以通过以下步骤来解决问题:

  • 计算每块巧克力的重量:给定每块巧克力的边长 a[i],巧克力的重量是 a[i]^2
  • 排序:为了最大化每个背包的装载量,我们将所有巧克力按重量升序排序,这样可以优先选择较轻的巧克力,尽量填满背包。
  • 背包查询:对于每个背包的最大承重,我们遍历排序后的巧克力重量数组,累加重量直到超过背包承重限制,记录最多能装入的巧克力数。

3. 代码解析

python

def solution(n: int, m: int, a: list, queries: list) -> list:
    # 计算每块巧克力的重量 (即边长的平方)
    weights = [x * x for x in a]
    
    # 将巧克力的重量进行排序
    weights.sort()
    
    # 计算对于每个背包,最多可以装多少块巧克力
    result = []
    
    # 对每个背包的最大承重进行查询
    for query in queries:
        total_weight = 0  # 当前背包的总重量
        count = 0  # 当前背包能装的巧克力数量
        
        for weight in weights:
            if total_weight + weight <= query:  # 如果加入当前巧克力不超重
                total_weight += weight
                count += 1
            else:
                break  # 如果超重,停止装入巧克力
        
        result.append(count)
    
    return result
    
    # 测试样例
if __name__ == '__main__':
    print(solution(5, 5, [1, 2, 2, 4, 5], [1, 3, 7, 9, 15]) == [1, 1, 2, 3, 3])
    print(solution(4, 3, [3, 1, 2, 5], [5, 10, 20]) == [2, 2, 3])
    print(solution(6, 4, [1, 3, 2, 2, 4, 6], [8, 12, 18, 25]) == [2, 3, 4, 4])

  • 计算巧克力的重量:首先,我们计算每块巧克力的重量(边长的平方),并存入 weights 列表。
  • 排序:通过 weights.sort() 对巧克力的重量进行升序排序。
  • 背包查询:对于每个背包的承重限制 query,我们使用循环遍历所有巧克力的重量,从最轻的巧克力开始装入背包。每次累加当前巧克力的重量,直到背包的总重量超出 query 为止。如果超重,停止累加。
  • 输出结果:最终,将每个背包的最大装载量记录在 result 数组中,最后返回这个结果。

4. 复杂度分析

  • 时间复杂度

    • 计算巧克力重量的时间复杂度是 O(n)。
    • 排序巧克力重量的时间复杂度是 O(n log n)。
    • 对于每个查询,需要遍历所有巧克力的重量,查询的时间复杂度是 O(n)。
    • 总的时间复杂度是 O(n log n + m * n),其中 n 是巧克力块数,m 是背包的数量。
  • 空间复杂度

    • 需要存储巧克力的重量数组 weights,空间复杂度是 O(n)。

5. 学习心得与总结

  • 二分查找的优化

    • 在上述实现中,我们通过按重量排序巧克力并遍历背包的最大承重进行查找,这种方法对于小规模问题有效。但当问题的规模增大时,查询每个背包的最大承重时的时间复杂度会变得较高。
    • 为了进一步优化性能,可以考虑用 二分查找 来快速找到背包能够容纳的最多巧克力块数。使用 bisect_right 来快速查找符合条件的最大数量,可以将查询时间从 O(n) 降低到 O(log n)。
  • 边界条件考虑

    • 当背包的最大承重小于最轻的巧克力块时,查询结果应为 0。
    • 当背包的最大承重大于或等于所有巧克力的总重量时,查询结果应为所有巧克力的数量。

6. 问题总结与代码问题分析

在最初的实现中,我们直接通过累加重量来判断背包的承载能力,但这种方式对于每个查询都需要遍历所有巧克力块,时间复杂度较高。针对背包容量较大时,可以使用二分查找的优化方法来提高查询效率。

学习建议:

  1. 注重算法优化:面对大规模数据时,考虑是否可以使用更高效的算法(例如二分查找、动态规划等)来降低时间复杂度。
  2. 问题拆解:将问题拆解为多个小问题进行处理,逐步优化每个部分,避免一次性做所有处理,减少不必要的复杂度。
  3. 多做题目:多做不同类型的题目,积累经验,不断优化解决方案。

总结:

通过解决这个问题,我更加深入地理解了如何通过排序和二分查找来优化查询过程,提升解决问题的效率。同时也提醒自己,面对不同的题目要灵活应用算法,选择最合适的方案。