36.饭馆菜品选择问题 | 豆包MarsCode AI刷题

46 阅读3分钟

问题描述

小 C 来到了一家饭馆,这里共有 n 道菜,第 i 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 i 道菜是否含有蘑菇。如果 s_i = '1',那么第 i 道菜含有蘑菇,否则没有。

小 C 希望点 k 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 m 道菜含有蘑菇。小 C 想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出 -1

测试样例

样例 1

输入:s = "001", a = [10, 20, 30], m = 1, k = 2

输出:30

样例 2

输入:s = "111", a = [10, 20, 30], m = 1, k = 2

输出:-1

样例 3

输入:s = "0101", a = [5, 15, 10, 20], m = 2, k = 3

输出:30

解题思路分析

这道题的核心是从nn道菜中选择kk道,使得总价格最低,同时满足含有蘑菇的菜品数量不超过mm。以下是详细思路:

步骤 1:分类菜品

根据是否含有蘑菇,将菜品分为两组: - 含有蘑菇的菜品(记为 with_mushroom); - 不含蘑菇的菜品(记为 without_mushroom)。

步骤 2:排序

对两组菜品分别按价格升序排序。这样可以方便地从每组中选出价格最低的菜品。

步骤 3:前缀和优化

为了快速计算选取某些菜品的总价格,使用前缀和技术。例如,排序后的菜品价格为 [5, 7, 10],前缀和为 [0, 5, 12, 22],表示从前ii道菜中选取的总价格。

步骤 4:组合选择

遍历可能选择的蘑菇菜品数量 xx (0xmin(m,len(with_mushroom)))(0 \leq x \leq \min(m, \text{len}(\text{with\_mushroom}))),计算对应的不含蘑菇菜品数量为 kxk - x

检查是否满足以下条件:

  • xx 道含蘑菇菜品的总数不超过 mm
  • kxk - x 道不含蘑菇菜品的总数不超过其总数量。如果满足条件,计算总价格并更新最小值。

步骤 5:返回结果

如果存在满足条件的组合,返回最小价格;否则返回 -1。

代码实现

def solution(s: str, a: list, m: int, k: int) -> int:
    # 将菜品分类
    with_mushroom = []  # 含蘑菇的菜品价格
    without_mushroom = []  # 不含蘑菇的菜品价格
    
    for i in range(len(s)):
        if s[i] == '1':
            with_mushroom.append(a[i])
        else:
            without_mushroom.append(a[i])
    
    # 对价格排序
    with_mushroom.sort()
    without_mushroom.sort()
    
    # 计算前缀和
    prefix_with_mushroom = [0] * (len(with_mushroom) + 1)
    prefix_without_mushroom = [0] * (len(without_mushroom) + 1)
    
    for i in range(1, len(prefix_with_mushroom)):
        prefix_with_mushroom[i] = prefix_with_mushroom[i - 1] + with_mushroom[i - 1]
    
    for i in range(1, len(prefix_without_mushroom)):
        prefix_without_mushroom[i] = prefix_without_mushroom[i - 1] + without_mushroom[i - 1]
    
    # 遍历选取蘑菇菜品的数量
    min_cost = float('inf')
    for mushrooms in range(min(len(with_mushroom), m) + 1):
        # 剩余需要选的不含蘑菇的菜品数量
        non_mushrooms = k - mushrooms
        
        # 检查是否可行
        if non_mushrooms >= 0 and non_mushrooms <= len(without_mushroom):
            # 计算总价格
            total_cost = prefix_with_mushroom[mushrooms] + prefix_without_mushroom[non_mushrooms]
            min_cost = min(min_cost, total_cost)
    
    return min_cost if min_cost != float('inf') else -1

总结

1. 贪心算法

贪心思想:通过排序后优先选择价格最低的菜品,逐步尝试组合以满足条件。

2. 前缀和

使用前缀和快速计算前xx道菜的总价格,减少重复计算,提升效率。

3. 边界条件

  • k>nk > nm<0m < 0,直接返回 -1。
  • 如果两组菜品的数量都不足以满足kk,则无法实现要求。

4. 优化时间复杂度

排序的复杂度为O(nlogn)O(n \log n),遍历组合的复杂度为O(min(k,m))O(\min(k, m))。整体复杂度为O(nlogn)O(n \log n),适合大规模数据处理。