philosyang.com

2080. Range Frequency Queries | 1702

I thought it was a prefix sum but I neglected that my initial idea is O(n^2) in memory:

 1class RangeFreqQuery:
 2    # intuition
 3    # we need O(1) query
 4    # subarray O(1) lookup makes me think of prefix sums
 5    # e.g., for everything to the left of 1 (inclusive): defaultdict(int) with {12: 1, 33: 1}
 6    # for everything to the left of 2 (inclusive): defaultdict(int) with {12: 1, 33: 1, 4: 1}
 7    # query 4 for [1, 2] means prefix2[4] - prefix0[4]
 8    # NOTE: this intuition MLEs, it is O(n^2) memory
 9
10    def __init__(self, arr: List[int]):
11        self.n = len(arr)
12        self.hash_list = [None] * self.n
13
14        self.hash_list[0] = defaultdict(int)
15        self.hash_list[0][arr[0]] += 1
16        for i in range(1, self.n):
17            temp_dict = self.hash_list[i - 1].copy()
18            temp_dict[arr[i]] += 1
19            self.hash_list[i] = temp_dict
20
21    def query(self, left: int, right: int, value: int) -> int:
22        if left == 0:
23            return self.hash_list[right][value]
24        return self.hash_list[right][value] - self.hash_list[left - 1][value]
25
26
27# Your RangeFreqQuery object will be instantiated and called as such:
28# obj = RangeFreqQuery(arr)
29# param_1 = obj.query(left,right,value)

Grouping things by the key being queried:

 1class RangeFreqQuery:
 2    # intuition #2
 3    # for each value, store a sorted list of indices where it appears
 4    # e.g., 33: [1, 7]
 5    # we can realize this structure in O(nlogn) with priority queue
 6    # NOTE: we actually don't need pq at all - since we traverse from left to right, .append promises sorted state
 7    # then, two binary search for each query solves it
 8
 9    def __init__(self, arr: List[int]):
10        self.d = defaultdict(list)
11        for i, value in enumerate(arr):
12            self.d[value].append(i)
13
14    def query(self, left: int, right: int, value: int) -> int:
15        return bisect_right(self.d[value], right) - bisect_left(self.d[value], left)
16
17
18# Your RangeFreqQuery object will be instantiated and called as such:
19# obj = RangeFreqQuery(arr)
20# param_1 = obj.query(left,right,value)

#Hashing #Binary-Search #Python