问题描述
小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[i] 的值,将菜品分为两组:
- 蘑菇菜:
mushrooms,满足 s[i]=′1′。 - 非蘑菇菜:
noMushrooms,满足 s[i]=′0′。
- 蘑菇菜:
-
-
排序:
- 对两组菜品分别按照价格升序排序,优先选取价格最低的菜品。
-
枚举蘑菇菜的选择数量:
- xxx:从
mushrooms中选择的菜的数量,范围是 [0,min(k,m)]。 - 从
noMushrooms中选择 k−x 道菜。
- xxx:从
-
验证组合可行性:
- 检查蘑菇菜或非蘑菇菜的数量是否足够满足当前选择。如果不足,跳过该组合。
-
计算总价格:
- 从
mushrooms中选前 x 个菜,从noMushrooms中选前 k−x 个菜,计算总价格。
- 从
-
输出结果:
- 遍历所有组合,记录最低总价格。如果无法满足条件,返回 −1。
Java代码实现
java
复制代码
import java.util.*;
public class Main {
public static long solution(String s, int[] a, int m, int k) {
List<Integer> mushrooms = new ArrayList<>();
List<Integer> noMushrooms = new ArrayList<>();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '1') {
mushrooms.add(a[i]);
} else {
noMushrooms.add(a[i]);
}
}
Collections.sort(mushrooms);
Collections.sort(noMushrooms);
long minCost = Long.MAX_VALUE;
boolean found = false;
for (int x = 0; x <= Math.min(k, m); x++) {
int y = k - x;
if (x > mushrooms.size() || y > noMushrooms.size()) {
continue;
}
long cost = 0;
for (int i = 0; i < x; i++) {
cost += mushrooms.get(i);
}
for (int i = 0; i < y; i++) {
cost += noMushrooms.get(i);
}
minCost = Math.min(minCost, cost);
found = true;
}
return found ? minCost : -1;
}
public static void main(String[] args) {
System.out.println(solution("001", new int[]{10, 20, 30}, 1, 2) == 30);
System.out.println(solution("111", new int[]{10, 20, 30}, 1, 2) == -1);
System.out.println(solution("0101", new int[]{5, 15, 10, 20}, 2, 3) == 30);
}
}
代码说明
-
分类和排序:
- 将含有蘑菇的菜和不含蘑菇的菜分别存入两个列表
mushrooms和noMushrooms。 - 对两个列表按价格升序排序,方便后续优先选择价格最低的菜品。
- 将含有蘑菇的菜和不含蘑菇的菜分别存入两个列表
-
枚举蘑菇菜数量:
- 遍历 x(选择的蘑菇菜数量),根据 y=k−x 计算需要的非蘑菇菜数量。
- 如果 x > mushrooms.size() 或 y > noMushrooms.size(),说明当前组合不可行,跳过。
-
计算总价格:
- 从
mushrooms和noMushrooms分别选择前 x 和 y 道菜,计算总价格并更新全局最小值。
- 从
-
输出结果:
- 如果找到符合条件的组合,返回最低总价格。
- 如果所有组合都不符合条件,返回 −1。
复杂度分析
-
时间复杂度:
- 分类菜品:O(n)。
- 排序:O(nlogn)。
- 枚举组合并计算价格:O(k^2),其中 k 是最多选择的菜品数量。
- 总复杂度:O(nlogn + k^2)。
-
空间复杂度:
- 使用了两个额外的列表存储菜品,空间复杂度为 O(n)。
总结
- 分类和排序是解决该问题的核心,通过排序优先选取价格最低的菜品。
- 通过穷举组合,验证所有可能的选择,确保找到最低总价格。
- 该方法时间复杂度较低,适合处理常见规模的输入。