受标签影响的最大值
题目
我们有一个 n 项的集合。给出两个整数数组 values
和 labels
,第 i 个元素的值和标签分别是 values[i]
和 labels[i]
。还会给出两个整数 numWanted
和 useLimit
。
从 n 个元素中选择一个子集 s
:
- 子集
s
的大小,小于或等于numWanted
。 s
中 最多 有相同标签的 useLimit 项。
一个子集的 分数 是该子集的值之和。
返回子集 s 的 最大分数 。
示例 1:
输入:values = [5,4,3,2,1], labels = [1,1,2,2,3], numWanted = 3, useLimit = 1
输出:9
解释:选出的子集是第一项,第三项和第五项。
示例 2:
输入:values = [5,4,3,2,1], labels = [1,3,3,3,2], numWanted = 3, useLimit = 2
输出:12
解释:选出的子集是第一项,第二项和第三项。
示例 3:
输入:values = [9,8,8,7,6], labels = [0,0,0,1,1], numWanted = 3, useLimit = 1
输出:16
解释:选出的子集是第一项和第四项。
提示:
n == values.length == labels.length
1 <= n <= 2 * 104
0 <= values[i], labels[i] <= 2 * 104
1 <= numWanted, useLimit <= n
分析题目
这道题读懂题目,会发现其实并不难,属于中等题中的简单题,但问题是题目写的让人难以理解,不明所以,所以分析题目是这道题的关键。
- 现在有等长的两个数组:
values
和labels
, 长度记作n
- 同时第
i
项的value
与label
正好对应的是:values[i]
与lables[i]
- 还会给出两个整数参数
numWanted
和useLimit
numWanted
代表子集的个数,useLimit
代表子集label
允许重复的个数- 要求从
n
个元素中,选择一个子集s
子集 s
的条件必须满足一下规则:
- 子集
s
的元素个数,即集合长度,小于或等于numWanted
- 子集
s
中最多有useLimit
个相同label
返回这满足子集条件的分数,即子集数组中每一个元素累加之和。
即, 由于 label
与 values
是对应关系, label
又存在重复项,所以我们需要从 label
中选择 useLimit
个最大值即可。
方法1:哈希表+排序
思路
根据题目分析,我们已经知道,只需要获取每个 label 的 useLimit
最大值即可,所以我们可以对 values
进行降序排序,排序完成后依次取值进行判断是否符合规则,同时使用 哈希表 记录每一种标签已经选择的个数即。
- 我们直接对
numWanted
进行自减,当numWanted
== 0 时,终止循环。 - 当 map 中的 label 个数等于
useLimit
时,跳过当前元素。
关于 values 与 labels 排序
因为 values 和 labels 是互相关联的两个数组,直接使用系统排序算法对两个数组进行排序会比较困难,需要手写实现,所以这里单独维护一个有序列表,当 values 与 labels 取值时,直接取 values[id[i]]
即可。
具体实现
Java 实现
1 |
|
JavaScript 实现
1 |
|
复杂度分析
- 时间复杂度: $O(n\ log_n)$ 排序算法时间复杂度为 $O(n\ log_n)$,后续遍历时间复杂度为 $O(n)$
- 空间复杂度: $O(n)$ 数组id 与 map 的空间复杂度都为 $O(n)$