题目描述
你需要在一个集合里动态记录 ID 的出现频率。给你两个长度都为 n
的整数数组 nums
和 freq
,nums
中每一个元素表示一个 ID,对应的 freq
中的元素表示这个 ID 在集合中此次操作后需要增加或者减少的数目。
- 增加 ID 的数目:如果
freq[i]
是正数,那么freq[i]
个 ID 为nums[i]
的元素在第i
步操作后会添加到集合中。 - 减少 ID 的数目:如果
freq[i]
是负数,那么-freq[i]
个 ID 为nums[i]
的元素在第i
步操作后会从集合中删除。
请你返回一个长度为 n
的数组 ans
,其中 ans[i]
表示第 i
步操作后出现频率最高的 ID 数目,如果在某次操作后集合为空,那么 ans[i]
为 0
。
样例
输入:nums = [2,3,2,1], freq = [3,2,-3,1]
输出:[3,3,2,2]
解释:
第 0 步操作后,有 3 个 ID 为 2 的元素,所以 ans[0] = 3。
第 1 步操作后,有 3 个 ID 为 2 的元素和 2 个 ID 为 3 的元素,所以 ans[1] = 3。
第 2 步操作后,有 2 个 ID 为 3 的元素,所以 ans[2] = 2。
第 3 步操作后,有 2 个 ID 为 3 的元素和 1 个 ID 为 1 的元素,所以 ans[3] = 2。
输入:nums = [5,5,3], freq = [2,-2,1]
输出:[2,0,1]
解释:
第 0 步操作后,有 2 个 ID 为 5 的元素,所以 ans[0] = 2。
第 1 步操作后,集合中没有任何元素,所以 ans[1] = 0。
第 2 步操作后,有 1 个 ID 为 3 的元素,所以 ans[2] = 1。
限制
1 <= nums.length == freq.length <= 10^5
1 <= nums[i] <= 10^5
-10^5 <= freq[i] <= 10^5
freq[i] != 0
- 输入保证任何操作后,集合中的元素出现次数不会为负数。
算法
(多重集) $O(m + n \log n)$
- 维护一个当前所有数字的频率数组以及一个频率的多重集。
- 每次操作时,先从多重集中删除之前这个数字的频率(如果存在),然后更新频率数组,最后再把这个数字的频率(如果存在)插入多重集。
- 如果多重集不为空,则将多重集的最大值写入答案。
时间复杂度
- 需要 $O(n + m)$ 的时间初始化频率数组和答案。
- 多重集每次操作的时间复杂度为 $O(\log n)$。
- 故总时间复杂度为 $O(m + n \log n)$。
空间复杂度
- 需要 $O(n + m)$ 的额外空间存储多重集、频率数组和答案。
C++ 代码
#define LL long long
const int N = 100010;
class Solution {
private:
LL cnt[N];
public:
vector<LL> mostFrequentIDs(vector<int>& nums, vector<int>& freq) {
const int n = nums.size();
vector<LL> ans(n, 0);
memset(cnt, 0, sizeof(cnt));
multiset<LL> h;
for (int i = 0; i < n; i++) {
if (cnt[nums[i]] > 0)
h.erase(h.find(cnt[nums[i]]));
cnt[nums[i]] += freq[i];
if (cnt[nums[i]] > 0)
h.insert(cnt[nums[i]]);
if (!h.empty())
ans[i] = *h.rbegin();
}
return ans;
}
};