如何在一个数组范围内找到给定数字的频率?

时间:2015-05-05 15:31:22

标签: c++ arrays frequency cumulative-frequency

问题是: 您将获得一个大小 N 的数组。同时给出 q =查询数量;在查询中,您将获得 l =较低范围, u =较高范围和 num =您需要计算频率的数量升〜U

我用C ++实现了我的代码,如下所示:

#include <iostream>
#include <map>

using namespace std;

map<int,int>m;

void mapnumbers(int arr[], int l, int u)
{
    for(int i=l; i<u; i++)
    {
        int num=arr[i];
        m[num]++;
    }
}


int main()
{
    int n; //Size of array
    cin>>n;

    int arr[n];

    for(int i=0; i<n; i++)
        cin>>arr[i];

    int q; //Number of queries
    cin>>q;

    while(q--)
    {
        int l,u,num;   //l=lower range, u=upper range, num=the number of which we will count frequency
        cin>>l>>u>>num;
        mapnumbers(arr,l,u);
        cout<<m[num]<<endl;
    }

    return 0;
}

但是我的代码有问题,在每个查询中它都没有使地图 m 为空。这就是为什么如果我查询相同的数字两次/三次,它会将频率计数与先前存储的频率相加。

我该如何解决这个问题? 对于大范围的查询,它是一个糟糕的程序,因为10 ^ 5? 什么是这个问题的有效解决方案?

4 个答案:

答案 0 :(得分:2)

您可以使用SQRT分解查询来解决任务。复杂性将是 O(M * SQRT(N))。首先,根据以下条件对所有查询进行排序:L / sqrt(N)应该增加,其中L是查询的左边界。对于相等的L / sqrt(N),R(右边界)也应该增加。 N是查询数。然后执行此操作:计算第一个查询的答案。然后,只需将此查询的边界移动逐个下一个查询的边界。例如,如果排序后的第一个查询是[2,7]而第二个是[1,10],则将左边界限移动到1并降低[2]的频率,增加1的频率。将右边界从7移动到10.增加[8],a [9]和[10]的频率。使用地图增加和减少频率。这是一项非常复杂的技术,但它可以很好地解决您的任务。您可以在此处阅读有关查询的SQRT分解的更多信息:LINK

答案 1 :(得分:0)

要清除地图,您需要致电map::clear()

void mapnumbers(int arr[], int l, int u)
{
    m.clear()

清除问题的更好方法是使m成为while (q--)循环的局部变量,甚至是mapnumbers函数。

然而,总的来说,为什么你需要地图是很奇怪的。无论如何,你遍历整个阵列,你知道你需要计算的数字,所以为什么不这样做

int mapnumbers(int arr[], int l, int u, int num)
{
    int result = 0;
    for(int i=l; i<u; i++)
    {
        if (arr[i] == num);
            result ++;
    }
    return result;
}

这将更快,甚至渐近更快,因为map操作是O(log N),因此您的原始解决方案针对每个查询运行O(N log N),而此简单迭代针对O(N)运行)。

然而,对于一个非常大的数组和许多查询(我猜问题来自一些竞争性的编程网站,不是吗?),这仍然是不够的。我想应该有一些允许O(log N)查询的数据结构和算法,虽然我现在也想不到。

UPD:我刚刚意识到数组不会改变您的问题。这使得它更加简单,允许每个查询解决方案使用简单的O(log N)。您只需要对输入数组中的所有数字进行排序,同时记住它们的原始位置(并确保排序稳定,以便原始位置按递增顺序排列);你只能这样做一次。在此之后,只需两次二进制搜索即可解决每个查询。

答案 2 :(得分:0)

许多算法可用于此类问题。这看起来像是一个直接的数据结构问题。您可以使用Segment树,Square Root Decomposition。检查Geeksforgeeks的算法!我告诉你学习算法的原因是,这种问题有如此大的约束,如果你使用你的方法,你的判决将是TLE。所以更好地使用算法。

答案 3 :(得分:0)

这里的许多答案都很复杂。我将告诉你找到范围频率的简便方法。您可以使用二进制搜索技术在每个查询的 O(logn)中获得答案。

为此,使用vector数组来存储数组中存在的所有数字的索引值,然后使用C ++ STL提供的lower_bound和upper_bound。

这是C ++代码:

    #define MAX 1000010

    std::vector<int> v[MAX];

    int main(){

    cin>>n;

    for (int i = 0; i < n; ++i)
    {
        cin>>a;
        v[a].push_back(i);
    }

    int low = 0, high = 0;

    int q; //Number of queries
    cin>>q;

    while(q--)
    {
        int l,u,num;   //l=lower range, u=upper range, num=the number of which we will count frequency
        cin>>l>>u>>num;
        low = lower_bound(v[num].begin(), v[num].end(), l) - v[num].begin();
        high = upper_bound(v[num].begin(), v[num].end(), u) - v[num].begin();
        cout<<(high - low)<<endl;
    }

    return 0;
}

总体时间复杂度: O(Q * log n)