题目
饭馆菜品选择问题
问题描述 小C来到了一家饭馆,这里共有 𝑛 n 道菜,第 𝑖 i 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 𝑖 i 道菜是否含有蘑菇。如果 s_i = '1',那么第 𝑖 i 道菜含有蘑菇,否则没有。
小C希望点 𝑘 k 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 𝑚 m 道菜含有蘑菇。小C想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出-1。
一、题目思路分析
- 需求理解:
- 题目给定了一系列菜品,每道菜有价格(用数组
a表示)和是否含蘑菇的属性(用字符串s表示)。要求在点菜时满足点k道菜,且所点菜品中最多只有m道菜含有蘑菇的条件下,使得总价格尽可能低。如果无法按要求选菜,则输出 -1。
- 解决思路及对应代码片段: - 菜品分类:
- 首先需要将菜品按照是否含蘑菇进行分类,分别统计不含蘑菇的菜品价格数组和含蘑菇的菜品价格数组,并记录各自的数量。 - 代码实现如下:
java int n = s.length(); int[] noMushroom = new int[n]; int[] mushroom = new int[n]; int noMushroomCount = 0, mushroomCount = 0; for (int i = 0; i < n; i++) { if (s.charAt(i) == '0') { noMushroom[noMushroomCount++] = a[i]; } else { mushroom[mushroomCount++] = a[i]; } }- - 排序操作:
-
- 然后对这两类菜品的价格数组分别进行排序,以便后续能方便地选取价格较低的菜品。 - 代码中使用
Arrays.sort方法实现排序:java Arrays.sort(noMushroom, 0, noMushroomCount); Arrays.sort(mushroom, 0, mushroomCount);
- 然后对这两类菜品的价格数组分别进行排序,以便后续能方便地选取价格较低的菜品。 - 代码中使用
-
- 利用优先队列计算最小总价格: - 接下来通过循环尝试不同数量的含蘑菇菜品(从0到
m与含蘑菇菜品实际数量的最小值),在每次尝试中,根据已确定的含蘑菇菜品数量,计算出还需要选择的不含蘑菇菜品数量,然后将相应的菜品价格相加得到一种点菜组合的总价格。 - 首先创建一个优先队列来存储不同组合的总价格:java PriorityQueue<Long> pq = new PriorityQueue<>();- 然后通过循环进行不同组合的尝试:java for (int i = 0; i <= Math.min(m, mushroomCount); i++) { if (k - i <= noMushroomCount) { long sum = 0; for (int j = 0; j < i; j++) { sum += mushroom[j]; } for (int j = 0; j < k - i; j++) { sum += noMushroom[j]; } pq.offer(sum); } }- 在上述循环中,对于每个可能的含蘑菇菜品数量i,先判断如果按照当前含蘑菇菜品数量i,剩余需要选择的不含蘑菇菜品数量(k - i)是否在不含蘑菇菜品数量的范围内(k - i <= noMushroomCount)。如果满足条件,就计算这种点菜组合的总价格sum,先累加i个含蘑菇菜品的价格(通过遍历含蘑菇菜品价格数组的前i个元素),再累加k - i个不含蘑菇菜品的价格(通过遍历不含蘑菇菜品价格数组的前k - i个元素),最后将sum放入优先队列pq中。
- 利用优先队列计算最小总价格: - 接下来通过循环尝试不同数量的含蘑菇菜品(从0到
-
- 返回结果: - 将所有满足条件的点菜组合总价格放入优先队列(小顶堆)中,这样优先队列的队首元素就是最小的总价格。最后根据优先队列是否为空来判断是否能满足点菜要求,如果不为空则返回队首元素作为最小总价格,否则返回 -1。 - 代码实现如下:
java return pq.isEmpty()? -1 : pq.poll();
- 返回结果: - 将所有满足条件的点菜组合总价格放入优先队列(小顶堆)中,这样优先队列的队首元素就是最小的总价格。最后根据优先队列是否为空来判断是否能满足点菜要求,如果不为空则返回队首元素作为最小总价格,否则返回 -1。 - 代码实现如下:
-
二、代码结构分析 1.
- 变量定义与初始化: - 在
solution方法中,首先获取菜品的总数n,然后定义了两个数组noMushroom和mushroom分别用于存储不含蘑菇和含蘑菇的菜品价格,同时定义了noMushroomCount和mushroomCount来记录这两类菜品的数量,初始值都为0。 -
- 菜品分类: - 通过遍历表示菜品是否含蘑菇的字符串
s和价格数组a,根据s.charAt(i)的值将菜品价格分别放入对应的noMushroom或mushroom数组中,并相应地更新noMushroomCount和mushroomCount。
- 菜品分类: - 通过遍历表示菜品是否含蘑菇的字符串
-
- 排序操作: - 使用
Arrays.sort方法对noMushroom数组和mushroom数组分别进行排序,排序范围是从索引0到各自的数量(noMushroomCount和mushroomCount),这样能保证数组内的价格是从小到大排列的,方便后续选取价格较低的菜品。
- 排序操作: - 使用
-
- 利用优先队列计算最小总价格: - 创建了一个
PriorityQueue<Long>类型的优先队列pq,它会自动按照元素的大小(这里是总价格)进行排序,默认是小顶堆,即队首元素是最小的。 - 通过一个循环,尝试不同数量的含蘑菇菜品(i从0到Math.min(m, mushroomCount))。在每次循环中,先判断如果按照当前含蘑菇菜品数量i,剩余需要选择的不含蘑菇菜品数量(k - i)是否在不含蘑菇菜品数量的范围内(k - i <= noMushroomCount)。如果满足条件,就计算这种点菜组合的总价格sum,先累加i个含蘑菇菜品的价格(通过遍历含蘑菇菜品价格数组的前i个元素),再累加k - i个不含蘑菇菜品的价格(通过遍历不含蘑菇菜品价格数组的前k - i个元素),最后将sum放入优先队列pq中。
- 利用优先队列计算最小总价格: - 创建了一个
-
- 返回结果: - 根据优先队列
pq是否为空来判断是否能满足点菜要求。如果pq为空,说明没有找到满足条件的点菜组合,返回 -1;否则,返回pq.poll(),即取出队首元素,也就是满足条件的最小总价格。
- 返回结果: - 根据优先队列