【Leetcode 每日一题】2080. 区间内查询数字的频率
问题背景
请你设计一个数据结构,它能求出给定子数组内一个给定值的 频率 。
子数组中一个值的 频率 指的是这个子数组中这个值的出现次数。
请你实现 RangeFreqQuery
类:
RangeFreqQuery(int[] arr)
用下标从 0 0 0 开始的整数数组 a r r arr arr 构造一个类的实例。int query(int left, int right, int value)
返回子数组 a r r [ l e f t . . . r i g h t ] arr[left...right] arr[left...right] 中 v a l u e value value 的 频率 。
一个 子数组 指的是数组中一段连续的元素。 a r r [ l e f t . . . r i g h t ] arr[left...right] arr[left...right] 指的是 n u m s nums nums 中包含下标 l e f t left left 和 r i g h t right right 在内 的中间一段连续元素。
数据约束
- 1 ≤ a r r . l e n g t h ≤ 1 0 5 1 \le arr.length \le 10 ^ 5 1≤arr.length≤105
- 1 ≤ a r r [ i ] , v a l u e ≤ 1 0 4 1 \le arr[i], value \le 10 ^ 4 1≤arr[i],value≤104
- 0 ≤ l e f t ≤ r i g h t < a r r . l e n g t h 0 \le left \le right \lt arr.length 0≤left≤right<arr.length
- 调用
query
不超过 1 0 5 10 ^ 5 105 次。
解题过程
频率相关的问题,大概率和哈希表有关,这题的困难之处也在于如何构造哈希表。
实际上需要建立的是每个元素,与它所有可能下标组成的列表之间的映射。
有了这样的数据之后,就可以用二分法确定要求的范围内到底有多少待查询元素存在了。
具体实现
class RangeFreqQuery {
private final Map<Integer, List<Integer>> map = new HashMap<>();
public RangeFreqQuery(int[] arr) {
for (int i = 0; i < arr.length; i++) {
map.computeIfAbsent(arr[i], key -> new ArrayList<>()).add(i);
}
}
public int query(int left, int right, int value) {
List<Integer> positions = map.get(value);
if (positions == null) {
return 0;
}
return binarySearch(positions, right + 1) - binarySearch(positions, left);
}
private int binarySearch(List<Integer> list, int target) {
int left = 0;
int right = list.size();
while (left < right) {
int mid = left + ((right - left) >>> 1);
if (list.get(mid) < target) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
}
/**
* Your RangeFreqQuery object will be instantiated and called as such:
* RangeFreqQuery obj = new RangeFreqQuery(arr);
* int param_1 = obj.query(left,right,value);
*/