子数组范围内出现的最大元素(模式查询)
给定一个包含N个整数的数组arr[]和一个包含M对的数组Q[] ,其中一对表示{L, R} 形式的查询,任务是找到范围[L, R]及其每个查询的频率。如果有多个具有最大频率的元素,则打印其中的最大元素。
例子:
Input: arr[] = {5, 7, 5, 5, 2, 7, 3, 2, 5, 2}, Q[] = {{0, 9}, {3, 6}, {4, 8}, {1, 5}}
Output: 5 Occurs 4 times
3 Occurs 1 times
2 Occurs 2 times
7 Occurs 2 times
Explanation:
The queries are performed as:
- Query(0, 9): The subarray over the range is {5, 7, 5, 5, 2, 7, 3, 2, 5, 2}. Elements 5, 7, 2, and 3 occur 4, 2, 3 and 1 times respectively. Therefore, print 5.
- Query(3, 6): The subarray over the range is {5, 2, 7, 3}. Every element occurs once. So print element 7.
- Query(4, 8): The subarray over the range is {2, 7, 3, 2, 5}. Element 2 occurs twice and the remaining all occurs once. Therefore, print 2.
- Query(1, 5): The subarray over the range is {7, 5, 5, 2, 7, 3}. Elements 7 and 5 occur twice and the remaining elements occur once. Therefore print 7.
朴素方法:对于每个查询,迭代给定范围 [L, R] 不断更新辅助数据结构(例如地图)中每个元素的频率。在处理完当前查询的整个范围后,遍历地图中的所有元素,找到具有最大频率的元素。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to find the elements having
// maximum frequency for the query range
void getMaxOccuringElement(int arr[], int N, int M,
pair Q[])
{
// Iterate over all the queries
for (int i = 0; i < M; ++i) {
// Stores the frequency of each element
// in the current query range [l, r]
map freq;
int l = Q[i].first, r = Q[i].second;
for (int j = l; j <= r; ++j)
++freq[arr[j]];
int maxFreqElement = -1;
int maxFreq = -1;
// Iterate over the map and find the
// element having maximum frequency
for (auto it : freq) {
if (it.second >= maxFreq) {
maxFreqElement = it.first;
maxFreq = it.second;
}
}
// Print the answer for current query
cout << maxFreqElement << " Occurs " << maxFreq
<< " times" << endl;
}
}
// Driver Code
int main()
{
int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
pair Q[]
= { { 0, 9 }, { 3, 6 }, { 4, 8 }, { 1, 5 } };
int N = sizeof(arr) / sizeof(arr[0]);
int M = sizeof(Q) / sizeof(Q[0]);
getMaxOccuringElement(arr, N, M, Q);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG{
static class pair
{
int first, second;
public pair(int first, int second)
{
this.first = first;
this.second = second;
}
}
// Function to find the elements having
// maximum frequency for the query range
static void getMaxOccuringElement(int arr[], int N, int M,
pair Q[])
{
// Iterate over all the queries
for (int i = 0; i < M; ++i) {
// Stores the frequency of each element
// in the current query range [l, r]
HashMap freq = new HashMap();
int l = Q[i].first, r = Q[i].second;
for (int j = l; j <= r; ++j) {
if(freq.containsKey(arr[j]))
freq.put(arr[j], freq.get(arr[j])+1);
else
freq.put(arr[j], 1);
}
int maxFreqElement = -1;
int maxFreq = -1;
// Iterate over the map and find the
// element having maximum frequency
for (Map.Entry it : freq.entrySet()) {
if (it.getValue() >= maxFreq) {
maxFreqElement = it.getKey();
maxFreq = it.getValue();
}
}
// Print the answer for current query
System.out.print(maxFreqElement+ " Occurs " + maxFreq
+ " times" +"\n");
}
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
pair Q[]
= { new pair( 0, 9 ), new pair( 3, 6 ), new pair( 4, 8 ), new pair( 1, 5 ) };
int N = arr.length;
int M = Q.length;
getMaxOccuringElement(arr, N, M, Q);
}
}
// This code contributed by Princi Singh
C#
// C# program for the above approach
using System;
using System.Collections.Generic;
public class GFG{
class pair
{
public int first, second;
public pair(int first, int second)
{
this.first = first;
this.second = second;
}
}
// Function to find the elements having
// maximum frequency for the query range
static void getMaxOccuringElement(int []arr, int N, int M,
pair []Q)
{
// Iterate over all the queries
for (int i = 0; i < M; ++i) {
// Stores the frequency of each element
// in the current query range [l, r]
Dictionary freq = new Dictionary();
int l = Q[i].first, r = Q[i].second;
for (int j = l; j <= r; ++j) {
if(freq.ContainsKey(arr[j]))
freq[arr[j]] = freq[arr[j]]+1;
else
freq.Add(arr[j], 1);
}
int maxFreqElement = -1;
int maxFreq = -1;
// Iterate over the map and find the
// element having maximum frequency
foreach (KeyValuePair it in freq) {
if (it.Value >= maxFreq) {
maxFreqElement = it.Key;
maxFreq = it.Value;
}
}
// Print the answer for current query
Console.Write(maxFreqElement+ " Occurs " + maxFreq
+ " times" +"\n");
}
}
// Driver Code
public static void Main(String[] args)
{
int []arr = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
pair []Q
= { new pair( 0, 9 ), new pair( 3, 6 ), new pair( 4, 8 ), new pair( 1, 5 ) };
int N = arr.Length;
int M = Q.Length;
getMaxOccuringElement(arr, N, M, Q);
}
}
// This code is contributed by 29AjayKumar
C++
// C++ program for the above approach
#include
using namespace std;
int BLOCK_SIZE;
// Structure to represent a query range
// and its index
struct query {
int l, r, idx;
};
// Custom comparator
bool comparator(query a, query b)
{
if ((a.l / BLOCK_SIZE) != (b.l / BLOCK_SIZE))
return (a.l / BLOCK_SIZE) < (b.l / BLOCK_SIZE);
return ((a.l / BLOCK_SIZE) & 1) ? (a.r < b.r)
: (a.r > b.r);
}
// Function to add elements to the current range
void expand(int idx, int* arr, map& numFreq,
set >& freqNum)
{
// Remove current element from the set
freqNum.erase({ numFreq[arr[idx]], arr[idx] });
// Increment current element count in the
// map
++numFreq[arr[idx]];
// Insert current element into the set
freqNum.insert({ numFreq[arr[idx]], arr[idx] });
}
// Function to remove elements from the current range
void shrink(int idx, int* arr, map& numFreq,
set >& freqNum)
{
// Remove current element from the set
freqNum.erase({ numFreq[arr[idx]], arr[idx] });
// Decrement current element count in the
// map
--numFreq[arr[idx]];
// Insert current element into the set
freqNum.insert({ numFreq[arr[idx]], arr[idx] });
}
// Function for Mo's algorithm
pair
sqrtDecomposition(int& L, int& R, int l, int r, int* arr,
set >& freqNum,
map& numFreq)
{
// Iterate until L is greater than l
while (L > l) {
--L;
expand(L, arr, numFreq, freqNum);
}
// Iterate until R is less than r
while (R < r) {
++R;
expand(R, arr, numFreq, freqNum);
}
// Iterate until L is less than l
while (L < l) {
shrink(L, arr, numFreq, freqNum);
++L;
}
// Iterate until R is greater than r
while (R > r) {
shrink(R, arr, numFreq, freqNum);
--R;
}
// Stores the answer for current query
pair last = *prev(freqNum.end());
// Return the answer
return last;
}
// Function to find the element having maximum
// frequency and its frequency for all the queries
void getMaxOccuringElement(int arr[], int N, int M,
pair Q[])
{
// Compute each block size
BLOCK_SIZE = (int)sqrt(N + .0) + 1;
// Stores the queries
query queries[M];
for (int i = 0; i < M; ++i) {
queries[i].l = Q[i].first;
queries[i].r = Q[i].second;
queries[i].idx = i;
}
// Sort all the queries
sort(queries, queries + M, comparator);
// Initiali ranges of Mos
int L = 0, R = -1;
// Stores the answer
pair ans[M];
set > freqNum;
map numFreq;
// Traverse the query array
for (int i = 0; i < M; ++i) {
int l = queries[i].l;
int r = queries[i].r;
// Stores the answer for current
// query
ans[queries[i].idx] = sqrtDecomposition(
L, R, l, r, arr, freqNum, numFreq);
}
// Print the answer
for (int i = 0; i < M; ++i) {
cout << ans[i].second << " Occurs " << ans[i].first
<< " times" << endl;
}
}
// Driver Code
int main()
{
int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
pair Q[]
= { { 0, 9 }, { 3, 6 }, { 4, 8 }, { 1, 5 } };
int N = sizeof(arr) / sizeof(arr[0]);
int M = sizeof(Q) / sizeof(Q[0]);
getMaxOccuringElement(arr, N, M, Q);
return 0;
}
输出
5 Occurs 4 times
7 Occurs 1 times
2 Occurs 2 times
7 Occurs 2 times
时间复杂度: O(M * N)
辅助空间: O(N)
Efficient Approach:上述方法可以通过基于sqrt分解概念的Mo's Algorithm进行优化。请按照以下步骤解决问题:
- 查询按其左索引所在的块的非递减顺序排序。如果两个或多个查询的左索引在同一个块中,则根据它们的右索引对它们进行排序。
- 基本上,计算所有查询的答案,这些查询的左索引在块 0 中,然后是块 1,依此类推,直到最后一个块。
- 维护一个映射数据结构 ( num_freq ),它存储当前查询范围内每个元素的出现次数。
- 另外,维护一个集合数据结构( freq_num ),它的每个元素都是一对(对的第一个元素表示元素的出现次数,对的第二个元素表示元素本身)。
- set( freq_num )以非递减顺序存储元素。集合中元素的排序基于该对的第一项,它表示频率。
- 因此,在回答查询(即具有最大频率的元素)时,可以在O(1)中完成。
以下是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
int BLOCK_SIZE;
// Structure to represent a query range
// and its index
struct query {
int l, r, idx;
};
// Custom comparator
bool comparator(query a, query b)
{
if ((a.l / BLOCK_SIZE) != (b.l / BLOCK_SIZE))
return (a.l / BLOCK_SIZE) < (b.l / BLOCK_SIZE);
return ((a.l / BLOCK_SIZE) & 1) ? (a.r < b.r)
: (a.r > b.r);
}
// Function to add elements to the current range
void expand(int idx, int* arr, map& numFreq,
set >& freqNum)
{
// Remove current element from the set
freqNum.erase({ numFreq[arr[idx]], arr[idx] });
// Increment current element count in the
// map
++numFreq[arr[idx]];
// Insert current element into the set
freqNum.insert({ numFreq[arr[idx]], arr[idx] });
}
// Function to remove elements from the current range
void shrink(int idx, int* arr, map& numFreq,
set >& freqNum)
{
// Remove current element from the set
freqNum.erase({ numFreq[arr[idx]], arr[idx] });
// Decrement current element count in the
// map
--numFreq[arr[idx]];
// Insert current element into the set
freqNum.insert({ numFreq[arr[idx]], arr[idx] });
}
// Function for Mo's algorithm
pair
sqrtDecomposition(int& L, int& R, int l, int r, int* arr,
set >& freqNum,
map& numFreq)
{
// Iterate until L is greater than l
while (L > l) {
--L;
expand(L, arr, numFreq, freqNum);
}
// Iterate until R is less than r
while (R < r) {
++R;
expand(R, arr, numFreq, freqNum);
}
// Iterate until L is less than l
while (L < l) {
shrink(L, arr, numFreq, freqNum);
++L;
}
// Iterate until R is greater than r
while (R > r) {
shrink(R, arr, numFreq, freqNum);
--R;
}
// Stores the answer for current query
pair last = *prev(freqNum.end());
// Return the answer
return last;
}
// Function to find the element having maximum
// frequency and its frequency for all the queries
void getMaxOccuringElement(int arr[], int N, int M,
pair Q[])
{
// Compute each block size
BLOCK_SIZE = (int)sqrt(N + .0) + 1;
// Stores the queries
query queries[M];
for (int i = 0; i < M; ++i) {
queries[i].l = Q[i].first;
queries[i].r = Q[i].second;
queries[i].idx = i;
}
// Sort all the queries
sort(queries, queries + M, comparator);
// Initiali ranges of Mos
int L = 0, R = -1;
// Stores the answer
pair ans[M];
set > freqNum;
map numFreq;
// Traverse the query array
for (int i = 0; i < M; ++i) {
int l = queries[i].l;
int r = queries[i].r;
// Stores the answer for current
// query
ans[queries[i].idx] = sqrtDecomposition(
L, R, l, r, arr, freqNum, numFreq);
}
// Print the answer
for (int i = 0; i < M; ++i) {
cout << ans[i].second << " Occurs " << ans[i].first
<< " times" << endl;
}
}
// Driver Code
int main()
{
int arr[] = { 5, 7, 5, 5, 2, 7, 3, 2, 5, 2 };
pair Q[]
= { { 0, 9 }, { 3, 6 }, { 4, 8 }, { 1, 5 } };
int N = sizeof(arr) / sizeof(arr[0]);
int M = sizeof(Q) / sizeof(Q[0]);
getMaxOccuringElement(arr, N, M, Q);
return 0;
}
输出
5 Occurs 4 times
7 Occurs 1 times
2 Occurs 2 times
7 Occurs 2 times
时间复杂度: O((N+M) * log(N) * sqrt(N))
辅助空间: O(N)