题目描述
我们有一个项的集合,其中第 i 项的值为 values[i],标签为 labels[i]。
我们从这些项中选出一个子集 S,这样一来:
- |S| <= num_wanted
- 对于任意的标签 L,子集 S 中标签为 L 的项的数目总满足 <= use_limit。
返回子集 S 的最大可能的 和。
示例1
输入:values = [5,4,3,2,1], labels = [1,1,2,2,3], num_wanted = 3, use_limit = 1
输出:9
解释:选出的子集是第一项,第三项和第五项。
示例2
输入:values = [5,4,3,2,1], labels = [1,3,3,3,2], num_wanted = 3, use_limit = 2
输出:12
解释:选出的子集是第一项,第二项和第三项。
示例3
输入:values = [9,8,8,7,6], labels = [0,0,0,1,1], num_wanted = 3, use_limit = 1
输出:16
解释:选出的子集是第一项和第四项。
示例4
输入:values = [9,8,8,7,6], labels = [0,0,0,1,1], num_wanted = 3, use_limit = 2
输出:24
解释:选出的子集是第一项,第二项和第四项。
思路
需要注意几点,相同的标签可能会被其他标签隔断,如label = [1,1,0,1,2,2],这个情况示例中没有。相同标签对应的value值不是有序排列的,如value = [2, 6, 3, 5, 4]. 首先利用优先队列对数据进行存储,将label有序存储,第二步,对于由相同label的value提取出来,有序存储在优先队列中,取前num个,存放在一个vector中,最后对vector进行逆序排序,取前num个相加得到的和为最终的结果。
实现
struct LabelValue {
int label;
int value;
LabelValue(int _label, int _value) : label(_label), value(_value){}
};
struct cmpLabelValue
{
bool operator()(LabelValue *&a, LabelValue *&b) const
{
return a->label < b->label;
}
};
int largestValsFromLabels(vector<int>& values, vector<int>& labels, int num_wanted, int use_limit) {
int oldLabel = -1;
int curLabel = 0;
int index = 0;
vector<int> data;
priority_queue<LabelValue*, vector<LabelValue*>, cmpLabelValue> newData;
priority_queue<int> number;
for (int i = 0; i < values.size(); i++)
{
LabelValue* labelValue = new LabelValue(labels[i], values[i]);
newData.push(labelValue);
}
while (!newData.empty())
{
curLabel = newData.top()->label;
int num = use_limit;
while (!newData.empty() && newData.top()->label == curLabel)
{
number.push(newData.top()->value);
newData.pop();
}
while (!number.empty() && num > 0)
{
data.push_back(number.top());
number.pop();
num--;
}
while (!number.empty())
{
number.pop();
}
}
sort(data.begin(), data.end());
reverse(data.begin(), data.end());
int res = 0;
for (int i = 0; i < num_wanted && i < data.size(); i++)
{
res += data[i];
}
return res;
}