问题描述
小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
解题思路
为了找到满足条件的最小总价格,我们需要高效地选择 k
道菜,其中最多只有 m
道菜含有蘑菇。
- 分类菜品并排序
- 将所有菜品分为两类:不含蘑菇的菜品 (
S
) 和 含蘑菇的菜品 (M
) - 将不含蘑菇的菜品和含蘑菇的菜品分别按价格从低到高排序。
- 序列和计算
- 为了快速计算任意数量菜品的总价格,计算两类菜品的序列和:
prefix_S[i]
表示从不含蘑菇的菜品中选择前i
道菜的总价格。prefix_M[i]
表示从含蘑菇的菜品中选择前i
道菜的总价格。
- 尝试不同的蘑菇菜品数量:
- 小C可以选择从
0
到min(m, len(M), k)
道含蘑菇的菜品。 - 对于每一个可能的选择
t
(含蘑菇的菜品数量):- 检查不含蘑菇的菜品数量是否足够
k - t
。 - 计算选择
t
道含蘑菇的菜品和k - t
道不含蘑菇的菜品的总价格。 - 记录所有可能选择中的最小总价格。
- 如果无法找到满足条件的组合(例如,所需的不含蘑菇的菜品数量超过实际可选数量),则返回
-1
。
- 检查不含蘑菇的菜品数量是否足够
算法流程
-
分类和排序
- 遍历所有菜品,将其分为含蘑菇和不含蘑菇两类。
- 分别对这两类菜品按价格升序排序。
-
计算序列和
- 分别计算不含蘑菇和含蘑菇的菜品的序列和,以便快速计算任意数量菜品的总价格。
-
遍历可能的蘑菇菜品数量
- 对于每一个可能的
t
(含蘑菇的菜品数量),计算对应的不含蘑菇的菜品数量。 - 检查是否满足选择条件,如果满足则计算总价格并更新最小值。
- 对于每一个可能的
-
返回结果
- 如果找到至少一种满足条件的组合,返回最小总价格。
- 否则,返回
-1
。
代码实现
def solution(s: str, a: list, m: int, k: int) -> int:
# 将菜品分为不含蘑菇和含蘑菇两类
S = [] # 不含蘑菇的菜品价格
M = [] # 含蘑菇的菜品价格
for si, ai in zip(s, a):
if si == '0':
S.append(ai)
else:
M.append(ai)
# 对两类菜品按价格升序排序
S.sort()
M.sort()
# 计算前缀和,以便快速计算任意数量菜品的总价格
prefix_S = [0] # prefix_S[i] 表示前 i 道不含蘑菇菜品的总价格
for price in S:
prefix_S.append(prefix_S[-1] + price)
prefix_M = [0] # prefix_M[i] 表示前 i 道含蘑菇菜品的总价格
for price in M:
prefix_M.append(prefix_M[-1] + price)
min_total = None # 用于记录最小总价格
# 尝试不同数量的含蘑菇菜品
max_t = min(m, len(M), k) # t 不能超过 m、含蘑菇菜品的数量和 k
for t in range(0, max_t + 1):
required_S = k - t # 需要的不含蘑菇菜品数量
if required_S <= len(S):
total = prefix_M[t] + prefix_S[required_S]
if (min_total is None) or (total < min_total):
min_total = total
# 返回结果
if min_total is not None:
return min_total
else:
return -1
if __name__ == '__main__':
print(solution("001", [10, 20, 30], 1, 2) == 30)
print(solution("111", [10, 20, 30], 1, 2) == -1)
print(solution("0101", [5, 15, 10, 20], 2, 3) == 30)
总结
通过将菜品分类、排序并利用序列和的方式,能够高效地找到满足条件的最小总价格。关键在于合理地将问题分解为两类菜品,并通过遍历不同的含蘑菇菜品数量来寻找最优解。