刷题记录2 | 豆包MarsCode AI刷题

39 阅读4分钟

问题描述

小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

解题:

参数:
- s (str): 长度为n的字符串,s_i代表第i道菜是否含有蘑菇('1'表示含有,'0'表示不含有)。
- a (list of int): 长度为n的整数列表,a_i代表第i道菜的价格。
- m (int): 所点的菜中最多可以含有m道蘑菇。
- k (int): 需要点的菜的数量。

返回:
- int: 满足条件的最小总价格。如果无法满足条件,则返回-1。
"""

# 分离菜品为不含蘑菇(Group A)和含蘑菇(Group B)的两组
group_A = [price for si, price in zip(s, a) if si == '0']
group_B = [price for si, price in zip(s, a) if si == '1']

# 如果k大于总菜品数,无法选择
if k > len(a):
    return -1

# 排序两组菜品,以便选择最便宜的
group_A_sorted = sorted(group_A)
group_B_sorted = sorted(group_B)

# 计算两组的前缀和,便于快速计算任意数量的最小总价格
prefix_A = [0]
for price in group_A_sorted:
    prefix_A.append(prefix_A[-1] + price)

prefix_B = [0]
for price in group_B_sorted:
    prefix_B.append(prefix_B[-1] + price)

# 初始化最小总价格为无穷大
min_total = float('inf')

# 遍历可能的含蘑菇菜品数量,从0到min(m, len(B), k))
max_b_count = min(m, len(group_B_sorted), k)
for b_count in range(0, max_b_count + 1):
    a_count = k - b_count  # 不含蘑菇的菜品数量

    # 检查是否有足够的不含蘑菇菜品
    if a_count <= len(group_A_sorted):
        total_price = prefix_A[a_count] + prefix_B[b_count]
        if total_price < min_total:
            min_total = total_price

# 如果找到有效的组合,返回最小总价格;否则,返回-1
return min_total if min_total != float('inf') else -1


-   **分组菜品**:

-   **Group A**(不含蘑菇的菜品):`s_i = '0'`
-   **Group B**(含蘑菇的菜品):`s_i = '1'`

这样,我们可以分别处理不含蘑菇和含蘑菇的菜品,便于后续选择最便宜的组合。
  • 排序

    • Group AGroup B中的菜品按价格从低到高进行排序。这样,我们可以轻松选择最便宜的菜品。
  • 前缀和计算

    • 计算Group AGroup B的前缀和。前缀和prefix_A[i]表示Group A中前i道菜的总价格,prefix_B[j]表示Group B中前j道菜的总价格。
    • 这样,在选择特定数量的菜品时,可以快速计算总价格。
  • 枚举含蘑菇菜品的数量

    • 遍历b_count从0到min(m, len(Group B), k),表示选择的含蘑菇菜品数量。
    • 对于每个b_count,计算需要从Group A中选择的菜品数量a_count = k - b_count
    • 检查是否有足够的Group A菜品供选择。如果有,计算总价格total_price = prefix_A[a_count] + prefix_B[b_count],并更新最小总价格min_total
  • 结果判断

    • 如果找到满足条件的组合,返回最小总价格。
    • 如果没有满足条件的组合(例如,无法选择足够的不含蘑菇的菜品),返回-1

复杂度分析:

  • 时间复杂度:

    • 分组和排序需要O(n log n)的时间,其中n是菜品数量。
    • 枚举b_count的范围为O(k)(实际为min(m, len(Group B), k)+1)。
    • 前缀和的计算和总价的比较均为O(n)。
    • 因此,总时间复杂度为O(n log n)。
  • 空间复杂度:

    • 需要额外的空间来存储Group AGroup B,以及它们的前缀和,空间复杂度为O(n)。

注意事项:

  1. 边界情况:

    • 当k = 0时,理论上总价为0,但根据题意,小C需要点k道菜,因此k >=1。
    • 当m = 0时,所有选中的菜品必须不含蘑菇。
    • 当m >= k时,可以选择所有k道菜都含蘑菇(如果需要)。
    • Group AGroup B不足以满足选择需求时,需返回-1。
  2. 输入有效性:

    • 确保字符串s和列表a的长度相同,即n = len(s) = len(a)。
    • 处理可能的重复菜品价格,虽然不影响总价格的计算。
  3. 优化:

    • 使用前缀和可以优化多次求和的操作,避免重复计算。