Implementing the class MajorityChecker
, which has the following API:
MajorityChecker(int[] arr)
constructs an instance of MajorityChecker with the given arrayarr
;int query(int left, int right, int threshold)
has arguments such that:0 <= left <= right < arr.length
representing a subarray ofarr
;2 * threshold > right - left + 1
, ie. the threshold is always a strict majority of the length of the subarray
Each query(...)
returns the element in arr[left], arr[left+1], ..., arr[right]
that occurs at least threshold
times, or -1
if no such element exists.
Example:
MajorityChecker majorityChecker = new MajorityChecker([1,1,2,2,1,1]); majorityChecker.query(0,5,4); // returns 1 majorityChecker.query(0,3,3); // returns -1 majorityChecker.query(2,3,2); // returns 2
Constraints:
1 <= arr.length <= 20000
1 <= arr[i] <= 20000
- For each query,
0 <= left <= right < len(arr)
- For each query,
2 * threshold > right - left + 1
- The number of queries is at most
10000
解題思路:
啥也不說了,精華全在這個題解中leetcode
方法一:線段樹
class MajorityChecker {
public:
MajorityChecker(vector<int>& arr) :nums(arr)
{
tree_nodes = vector<int>(4 * arr.size() , -1) ;
for(int i = 0 ; i < arr.size() ; i++) num_poses[arr[i]].push_back(i) ;
build_tree(1 , 0 , nums.size() - 1) ;
}
int query(int left, int right, int threshold)
{
auto res = query(1 , 0 , nums.size() - 1 , left , right) ;
if(res.first != -1)
{
if(res.second >= threshold) return res.first ;
else return -1 ;
}
else return -1 ;
}
void build_tree(int node , int left , int right)
{
if(left == right)
{
tree_nodes[node] = nums[left] ;
return ;
}
int mid = left + (right - left) / 2 ;
build_tree(2 * node , left , mid) ;
build_tree(2 * node + 1 , mid + 1 , right) ;
if(tree_nodes[2 * node] != -1 && getOccurrences(tree_nodes[2 * node] , left , right) * 2 > right - left + 1)
{
tree_nodes[node] = tree_nodes[2 * node] ;
return ;
}
if(tree_nodes[2 * node + 1] != -1 && getOccurrences(tree_nodes[2 * node + 1] , left , right) * 2 > right - left + 1)
{
tree_nodes[node] = tree_nodes[2 * node + 1] ;
}
}
int getOccurrences(int num , int left , int right)
{
if(left > right) return 0 ;
vector<int>& poses = num_poses[num] ;
auto iter_l = lower_bound(poses.begin() , poses.end() , left) ;
if(iter_l == poses.end()) return 0 ;
auto iter_r = upper_bound(poses.begin() , poses.end() , right) ;
return iter_r - iter_l ;
}
pair<int , int> query(int node , int left , int right , int queryl , int queryr)
{
if(left > queryr || right < queryl) return {-1 , -1} ;
if(left >= queryl && right <= queryr)
{
int num = tree_nodes[node] ;
if(num == -1) return {-1 , -1} ;
int cnt = getOccurrences(num , queryl , queryr) ;
if(cnt * 2 > queryr - queryl + 1) return {num , cnt} ;
return {-1 , -1} ;
}
int mid = left + (right - left) / 2 ;
pair<int , int> res = query(2 * node , left , mid , queryl , queryr) ;
if(res.first != -1) return res ;
res = query(2 * node + 1 , mid + 1 , right , queryl , queryr) ;
if(res.first != -1) return res ;
return {-1 , -1} ;
}
private :
vector<int> nums ;
vector<int> tree_nodes ;
unordered_map<int , vector<int>> num_poses ;
};
/**
* Your MajorityChecker object will be instantiated and called as such:
* MajorityChecker* obj = new MajorityChecker(arr);
* int param_1 = obj->query(left,right,threshold);
*/
方法二:概率
class MajorityChecker {
private:
unordered_map<int, vector<int>> pos;
vector<int> a;
int try_bound;
public:
MajorityChecker(vector<int>& arr): a(arr) {
srand(time(nullptr));
for (int i = 0; i < arr.size(); ++i) {
pos[arr[i]].push_back(i);
}
try_bound = 20;
}
int get_occurrence(int num, int l, int r) {
auto iter = pos.find(num);
if (iter == pos.end()) {
return 0;
}
const auto& vec = iter->second;
auto iter_l = lower_bound(vec.begin(), vec.end(), l);
if (iter_l == vec.end()) {
return 0;
}
auto iter_r = upper_bound(vec.begin(), vec.end(), r);
return iter_r - iter_l;
}
int get_random(int l, int r) {
return rand() % (r - l + 1) + l;
}
int query(int left, int right, int threshold) {
for (int i = 0; i < try_bound; ++i) {
int elem = a[get_random(left, right)];
if (get_occurrence(elem, left, right) >= threshold) {
return elem;
}
}
return -1;
}
};
/**
* Your MajorityChecker object will be instantiated and called as such:
* MajorityChecker* obj = new MajorityChecker(arr);
* int param_1 = obj->query(left,right,threshold);
*/