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

61 阅读3分钟

问题描述

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

小C希望点 kk 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 mm 道菜含有蘑菇。小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


解决这个问题的思路如下:

分析

  1. 菜的分类

    • 把菜分为两类:含有蘑菇的菜(s[i] = '1')和不含蘑菇的菜(s[i] = '0')。
    • 分别对这两类菜进行价格排序,以便选出最便宜的菜。
  2. 选择策略

    • 如果小C需要选的菜总数为 k,且最多有 m 道菜可以含有蘑菇,那么可以尝试不同的组合:

      • 选 x 道不含蘑菇的菜,其中 x 从 max⁡(0,k−m) 到 min⁡(k,无蘑菇菜的总数)。
      • 剩余的 k−x道菜必须从含有蘑菇的菜中选择。
    • 对于每种组合,计算总价格,选择满足条件的最小价格。

  3. 无法满足条件的情况

    • 如果不可能选出 k 道菜,输出 -1。

实现步骤

  1. 分离无蘑菇菜和有蘑菇菜,分别存储其价格。
  2. 对两类菜的价格进行升序排序。
  3. 使用双指针或者前缀和的方法,快速计算选定数量的菜品的最低价格。
  4. 遍历可能的 x 值(无蘑菇菜的数量),计算总价格,记录最小值。
  5. 返回结果。

以下是代码实现:

def min_price(s, a, m, k):
    # 将含有蘑菇和无蘑菇的菜分开
    no_mushroom = []
    with_mushroom = []
    
    for i in range(len(s)):
        if s[i] == '0':
            no_mushroom.append(a[i])
        else:
            with_mushroom.append(a[i])
    
    # 对两类菜进行排序
    no_mushroom.sort()
    with_mushroom.sort()
    
    # 如果总菜数不够 k 道菜,直接返回 -1
    if len(no_mushroom) + len(with_mushroom) < k:
        return -1
    
    # 计算前缀和,方便快速求和
    prefix_no_mushroom = [0] * (len(no_mushroom) + 1)
    prefix_with_mushroom = [0] * (len(with_mushroom) + 1)
    
    for i in range(1, len(no_mushroom) + 1):
        prefix_no_mushroom[i] = prefix_no_mushroom[i - 1] + no_mushroom[i - 1]
    
    for i in range(1, len(with_mushroom) + 1):
        prefix_with_mushroom[i] = prefix_with_mushroom[i - 1] + with_mushroom[i - 1]
    
    # 尝试不同的 x 值
    min_cost = float('inf')
    for x in range(max(0, k - m), min(k, len(no_mushroom)) + 1):
        y = k - x  # 含有蘑菇的菜的数量
        if y <= len(with_mushroom):
            cost = prefix_no_mushroom[x] + prefix_with_mushroom[y]
            min_cost = min(min_cost, cost)
    
    return min_cost if min_cost != float('inf') else -1

# 测试样例
print(min_price("001", [10, 20, 30], 1, 2))  # 输出:30
print(min_price("111", [10, 20, 30], 1, 2))  # 输出:-1
print(min_price("0101", [5, 15, 10, 20], 2, 3))  # 输出:30

代码说明

  1. 分类和排序

    • 把所有菜按是否含蘑菇分成两类,然后分别排序,以便优先选出最便宜的菜。
  2. 前缀和

    • 用前缀和快速计算任意数量的菜品的总价格。
  3. 组合尝试

    • 遍历 xx 值,表示选取的无蘑菇菜的数量,动态计算总价格,并更新最小值。
  4. 边界处理

    • 如果总菜数不足 kk,直接返回 -1。
    • 如果某种组合无法满足条件,也不会更新最小值。

复杂度分析

  1. 时间复杂度

    • 排序:O(nlog⁡n)。
    • 遍历组合:O(k)。
    • 总复杂度:O(nlog⁡n)。
  2. 空间复杂度

    • 需要额外的前缀和数组,空间复杂度为 O(n)。