📌  相关文章
📜  子数组范围内出现的最大元素(模式查询)

📅  最后修改于: 2022-05-13 01:57:47.855000             🧑  作者: Mango

子数组范围内出现的最大元素(模式查询)

给定一个包含N个整数的数组arr[]和一个包含M对的数组Q[] ,其中一对表示{L, R} 形式的查询,任务是找到范围[L, R]及其每个查询的频率。如果有多个具有最大频率的元素,则打印其中的最大元素。

例子:

朴素方法:对于每个查询,迭代给定范围 [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)