问题描述
假设我们有若干种菜品,每种菜品可能含有蘑菇,也可能不含蘑菇。每道菜的价格和是否含蘑菇已知。现在需要从这些菜品中选出 k 道菜,且含蘑菇的菜品数量最多为 m,以满足用户对蘑菇的限制条件。目标是使选择的菜品总价格最小。
解决方案
我们可以使用贪心算法解决这个问题,通过以下步骤实现:
-
分类菜品
- 将菜品根据是否含有蘑菇分为两类,分别存储在
mushroom(含蘑菇)和no_mushroom(不含蘑菇)列表中。
- 将菜品根据是否含有蘑菇分为两类,分别存储在
-
排序
- 将两个列表中的菜品按价格从低到高排序,以便优先选择价格最低的菜。
-
枚举分配方案
- 枚举选择含蘑菇菜的数量
x(0 <= x <= m且x <= k),根据x计算需要选择的不含蘑菇的菜数量y = k - x。 - 如果
x或y超过各自类别菜品的数量,则跳过该方案。
- 枚举选择含蘑菇菜的数量
-
计算总价格
- 对每种分配方案,计算从两类菜中选出的价格总和,并记录最小值。
-
结果返回
- 如果没有找到满足条件的方案,返回
-1;否则返回最小总价格。
- 如果没有找到满足条件的方案,返回
实现代码
def solution(s: str, a: list, m: int, k: int) -> int:
# 将菜品分为含蘑菇和不含蘑菇两类
mushroom = []
no_mushroom = []
for i in range(len(s)):
if s[i] == '1':
mushroom.append(a[i])
else:
no_mushroom.append(a[i])
# 按价格升序排序
mushroom.sort()
no_mushroom.sort()
# 如果菜品总数不足 k 道,直接返回 -1
if len(mushroom) + len(no_mushroom) < k:
return -1
# 滑动窗口枚举选择方案
min_price = float('inf')
for x in range(0, min(m + 1, k + 1)): # x 表示选择的含蘑菇菜的数量
y = k - x # y 表示选择的不含蘑菇菜的数量
if x > len(mushroom) or y > len(no_mushroom):
continue
# 计算当前组合的总价格
price = sum(mushroom[:x]) + sum(no_mushroom[:y])
min_price = min(min_price, price)
return min_price if min_price != float('inf') else -1
代码解析
-
分类
- 遍历字符串
s,判断每道菜是否含有蘑菇,将价格加入相应列表中。
- 遍历字符串
-
排序
- 对两个列表分别按价格升序排序,使得选择最便宜的菜变得高效。
-
枚举选择方案
- 遍历可能的蘑菇菜数量
x,根据需求计算不含蘑菇菜的数量y。 - 跳过无法满足条件的方案(如所需菜品数量超出类别数量)。
- 遍历可能的蘑菇菜数量
-
计算价格
- 对于每种合法的组合,计算其总价格并更新最小价格。
-
返回结果
- 如果存在符合条件的组合,返回最小总价格;否则返回
-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
print(solution("101", [5, 10, 15], 1, 2)) # 输出: 15
print(solution("000", [5, 10, 15], 1, 2)) # 输出: 15
测试样例结果分析
测试样例 1:
- 输入:
s = "001",a = [10, 20, 30],m = 1,k = 2 - 输出:
30 - 分析:选择不含蘑菇的两道菜(
10和20),总价为30。
测试样例 2:
- 输入:
s = "111",a = [10, 20, 30],m = 1,k = 2 - 输出:
-1 - 分析:所有菜都含蘑菇,而蘑菇菜数量上限为
1,无法满足条件。
测试样例 3:
- 输入:
s = "0101",a = [5, 15, 10, 20],m = 2,k = 3 - 输出:
30 - 分析:选择
5和10(不含蘑菇)以及15(含蘑菇),总价为30。
测试样例 4:
- 输入:
s = "101",a = [5, 10, 15],m = 1,k = 2 - 输出:
15 - 分析:选择
5(不含蘑菇)和10(含蘑菇),总价为15。
时间复杂度分析
- 分类和排序:O(n + n log n) = O(n log n),其中
n是菜品数量。 - 枚举选择方案:最多枚举
m + 1次,每次计算总价格需要 O(k)。 - 总体复杂度:O(n log n + m * k)。
总结
- 贪心思想:通过优先选择价格最低的菜品,尽可能降低总成本。
- 高效实现:使用分类、排序和滑动窗口的结合,减少计算复杂度。
- 适用场景:该方法适用于需要根据多条件优化选择问题的场景。
希望这篇文章能够帮助你深入理解该问题的解决思路和实现方法!