问题描述
小C来到了一家饭馆,这里共有 nn 道菜,第 ii 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 ii 道菜是否含有蘑菇。如果 s_i = '1',那么第 ii 道菜含有蘑菇,否则没有。
小C希望点 kk 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 mm 道菜含有蘑菇。小C想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出-1。
分析问题
-
输入:
s: 一个字符串,表示每道菜是否含有蘑菇。a: 一个整数数组,表示每道菜的价格。m: 整数,表示最多可以选含有蘑菇的菜的数量。k: 整数,表示总共需要选的菜的数量。
-
简化:
- 容器a中每个数的位置标号对应s中的位置,最多只能携带m个标号为1的数,返回最少k个数的和
- 可以使用一个
pair数组来存储每道菜的价格和是否含有蘑菇的信息。
算法步骤
-
初始化:
- 创建一个
pair数组,存储每道菜的价格和是否含有蘑菇的信息。 - 对
pair数组按价格从小到大排序。
- 创建一个
-
选择菜品:
- 遍历排序后的
pair数组,优先选择价格较低的菜。 - 使用两个计数器:一个记录已经选择的含有蘑菇的菜的数量,另一个记录已经选择的菜的总数量。
- 如果当前菜含有蘑菇且含有蘑菇的菜的数量未达到上限
m,则选择该菜。 - 如果当前菜不含蘑菇,则直接选择该菜。
- 如果已经选择了
k道菜,则停止选择。
- 遍历排序后的
-
检查结果:
- 如果已经选择了
k道菜,则返回总价格。 - 如果无法选择
k道菜,则返回-1。
- 如果已经选择了
代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
long long solution(const std::string &s, std::vector<int> &a, int m, int k) {
int n = a.size();
// 创建一个pair数组,包含数值和对应的s中的标记
std::vector<std::pair<int, char>> pairs;
for (int i = 0; i < n; i++) {
pairs.push_back({a[i], s[i]});
}
// 按照数值大小对pairs进行排序,数值小的在前
std::sort(pairs.begin(), pairs.end());
int onesSelected = 0;
long long sum = 0;
// 遍历排序后的pairs,选择最小的k个数
for (const auto &pair : pairs) {
if (k == 0) {
break;
}
if (pair.second == '0') {
sum += pair.first;
k--;
} else if (onesSelected < m) {
sum += pair.first;
k--;
onesSelected++;
}
}
// 如果k不为0,说明我们没有足够的'0'来满足k的需求,返回-1
if (k != 0) {
return -1;
}
return sum;
}
分析时间复杂度
-
创建pair数组:
- 这一步涉及到遍历字符串
s和数组a的长度n,将每个元素和对应的字符放入pairs数组中。这一步的时间复杂度是O(n)。
- 这一步涉及到遍历字符串
-
排序pairs数组:
- 使用
std::sort对pairs数组进行排序,排序算法通常是快速排序、堆排序或归并排序,平均时间复杂度为O(n log n)。
- 使用
-
遍历pairs数组:
- 这一步涉及到遍历排序后的
pairs数组,最坏情况下需要遍历整个数组,即O(n)。但在最佳情况下,可能只需要遍历k个元素,即O(k)。
- 这一步涉及到遍历排序后的
综合以上步骤,整个算法的时间复杂度主要由排序步骤决定,因此整体时间复杂度为O(n log n),其中n是数组a的长度。