题目描述
难度分:793
输入n(1≤n≤2×105)和长为n的数组a(1≤a[i]≤n),下标从1开始。
然后输入q个询问,每个询问输入L,R(1≤L≤R≤n)和x(1≤x≤n)。
对每个询问,输出有多少个下标i在[L,R]内的a[i],满足a[i]=x。
输入样例
5
3 1 4 1 5
4
1 5 1
2 4 3
1 5 2
1 3 3
输出样例
2
0
0
1
算法
二分查找
先用哈希表构建映射“值 → 出现的索引列表”val2pos,然后对于每个查询(l,r,x),二分查找x在列表val2pos[x]中的出现范围即可。即第一个大于等于l的位置j,第一个大于r的位置k,k−j就是x在子数组[l,r]出现的次数。
复杂度
时间复杂度
遍历一遍数组将不同值的索引进行分组时间复杂度是O(n),对于每个query,二分查找确定范围时间复杂度是O(log2n)的,因此算法的整体时间复杂度为O(n+qlog2n)。
空间复杂度
开辟了一个哈希表对数组中的元素按值分组,一共存了O(n)规模的索引,最差情况下数组中都是各不相同的值,存了2n级别的元素,额外空间复杂度仍然是O(n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <array>
#include <vector>
#include <unordered_map>
using namespace std;
const int N = 200010;
int a[N], n;
int main() {
scanf("%d", &n);
unordered_map<int, vector<int>> val2pos;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
val2pos[a[i]].push_back(i);
}
int q;
scanf("%d", &q);
while(q--) {
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
auto& v = val2pos[x];
int j = lower_bound(v.begin(), v.end(), l) - v.begin();
int k = upper_bound(v.begin(), v.end(), r) - v.begin();
printf("%d\n", max(0, k - j));
}
return 0;
}