问题描述
小C来到了一家饭馆,这里共有 n 道菜,第 i 道菜的价格为 a[i]。其中一些菜含有蘑菇,s[i] 代表第 i 道菜是否含有蘑菇。如果 s[i] = '1',表示该菜含有蘑菇,否则没有。
小C希望点 k 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 m 道菜含有蘑菇。小C想知道在满足条件的情况下,能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出 -1。
解题思路
这个问题可以通过贪心算法和分类处理来解决。我们可以将菜品分为两类:含蘑菇的菜和不含蘑菇的菜。然后通过对这两类菜品的价格进行排序,尽量选择价格最小的菜品,满足小C的要求。
思路解析:
-
菜品分类:
- 通过
s[i]判断菜品是否含有蘑菇,分别将含有蘑菇的菜品和不含蘑菇的菜品分开。
- 通过
-
排序:
- 对含蘑菇的菜品和不含蘑菇的菜品分别按价格从小到大排序,确保我们每次选择最便宜的菜品。
-
菜品选择:
- 我们需要选择
k道菜,并且最多选择m道含有蘑菇的菜。因此,选择含蘑菇的菜品的数量应该在0到m之间。 - 对于每一种可能的选择含蘑菇的菜品的数量,计算总价格,选出最小的价格。
- 我们需要选择
-
验证是否可行:
- 检查在某一选择下,是否能够选择足够数量的菜品。如果无法满足条件,则输出
-1。
- 检查在某一选择下,是否能够选择足够数量的菜品。如果无法满足条件,则输出
代码实现
def solution(s: str, a: list, m: int, k: int) -> int:
# 划分菜品为含蘑菇和不含蘑菇的菜
mushroom_dishes = []
non_mushroom_dishes = []
for i in range(len(s)):
if s[i] == '1':
mushroom_dishes.append(a[i])
else:
non_mushroom_dishes.append(a[i])
# 对这两类菜品分别排序
mushroom_dishes.sort()
non_mushroom_dishes.sort()
# 枚举蘑菇菜品数量的取值
min_cost = float('inf')
for x in range(0, min(m, k) + 1): # x 表示选择蘑菇菜品的数量
y = k - x # y 表示选择不含蘑菇菜品的数量
# 如果选择的菜品数量超过了可选的数量,跳过
if x > len(mushroom_dishes) or y > len(non_mushroom_dishes):
continue
# 计算当前选择方案的总价格
cost = sum(mushroom_dishes[:x]) + sum(non_mushroom_dishes[:y])
min_cost = min(min_cost, cost)
# 如果没有有效方案,返回 -1
return min_cost if min_cost != float('inf') else -1
代码解释
-
数据分类:
- 使用两个列表
mushroom_dishes和non_mushroom_dishes分别存储含有蘑菇和不含蘑菇的菜品的价格。
- 使用两个列表
-
排序:
- 对
mushroom_dishes和non_mushroom_dishes分别进行升序排序,确保我们可以选择价格最小的菜品。
- 对
-
枚举蘑菇菜品数量:
- 使用变量
x表示选择的蘑菇菜品数量,枚举的范围是0到min(m, k),即最多选择m道蘑菇菜品,且总共需要选择k道菜品。 - 对于每一个选择蘑菇菜品的数量
x,计算需要选择不含蘑菇的菜品数量y = k - x。
- 使用变量
-
判断是否可行:
- 如果选择的蘑菇菜品数量
x超过了实际可选的数量,或者选择的非蘑菇菜品数量y超过了实际可选的数量,则跳过该情况。
- 如果选择的蘑菇菜品数量
-
计算总价格:
- 对于每一种可行的选择,计算总价格,并更新最小总价格。
-
返回结果:
- 如果找到可行的方案,返回最小总价格;否则返回
-1。
- 如果找到可行的方案,返回最小总价格;否则返回
复杂度分析
-
时间复杂度:
- 将菜品分为两类需要
O(n)的时间。 - 对这两类菜品进行排序分别需要
O(n log n)的时间。 - 枚举蘑菇菜品数量需要
O(min(m, k)),每次枚举时的计算为常数时间。 - 综合时间复杂度为
O(n log n)。
- 将菜品分为两类需要
-
空间复杂度:
- 使用了两个列表来存储菜品信息,空间复杂度为
O(n)。
- 使用了两个列表来存储菜品信息,空间复杂度为
测试用例
测试用例 1
输入:
s = "001"
a = [10, 20, 30]
m = 1
k = 2
输出:
30
解释:有 3 道菜,正反面数字分别为 (10, 20), (20, 30), (30, 10)。选择 2 道菜,且最多选择 1 道蘑菇菜品,最小的总价格是 30。
测试用例 2
输入:
s = "111"
a = [10, 20, 30]
m = 1
k = 2
输出:
-1
解释:有 3 道菜,且每道菜都含有蘑菇,但只能选择最多 1 道蘑菇菜品,因此无法选择符合条件的菜品。
测试用例 3
输入:
s = "0101"
a = [5, 15, 10, 20]
m = 2
k = 3
输出:
30
解释:有 4 道菜,选择 3 道菜,且最多选择 2 道蘑菇菜品,最小的总价格是 30。
总结
这道题目考察了如何将问题分解为子问题,并利用排序和枚举来优化解法。通过合理分类和选择,我们可以快速找到最优解