处理大型数组时超出时间限制
Posted
技术标签:
【中文标题】处理大型数组时超出时间限制【英文标题】:Time Limit Exceeded in dealing with large arrays 【发布时间】:2014-11-11 05:39:08 【问题描述】:我正在尝试解决this question:
我们都知道 Varchas 正在进行中。所以 FOC 想组织一个名为“发现事件”的活动。
任务很简单:
给定一个正整数数组 A[1...N]。会有Q查询。在查询中,您将获得一个整数。您需要找出给定数组中该整数的频率。
输入:
输入的第一行包含整数 N,即给定数组中的整数个数。 下一行将包含 N 个空格分隔的整数。下一行是 Q,查询数。 接下来的 Q 行将包含一个整数,您应该找出它的出现次数。
输出:
为每个查询输出单个整数,即给定整数的频率。
约束:
1
1
0
这是我的代码:
#include <iostream>
using namespace std;
int main()
long long n=0;
cin >> n;
long long a[1000000];
for (int i=1;i<=n;i++)
cin >> a[i];
long long q=0;
cin >> q;
while (q--)
long long temp=0,counter=0;
cin >> temp;
for (int k=1;k<=n;k++)
if (a[k]==temp)
counter++;
cout << "\n" << counter;
temp=0;
counter=0;
return 0;
但是,我遇到了“超出时间限制”错误。我怀疑这是由于无法处理数组中的大值。谁能告诉我如何处理这么大的数组?
【问题讨论】:
请让您的问题自给自足,而不是提供链接。 问题要求您首先对数组进行排序,然后对于每个查询,您只需进行二进制搜索并找到包含该值的范围并打印范围的长度 问题是每次查询,都需要扫描整个数组,时间复杂度为O(n^2),显然是TLE @Smac89:问题不在于范围查询,它比这简单得多。问题是要求计算整数的频率。 啊,我知道你们现在在做什么。我通常会追求内存效率,因为你们依赖于 Q 很小的事实。这很好,但它不适用于大 Q 【参考方案1】:失败在于算法本身,请注意,对于每个查询,您都会遍历整个数组。有 100,000 个查询和 100,000 个元素。这意味着在更坏的情况下,您将遍历 100,000 * 100,000 个元素 = 10,000,000,000 个元素,这不会及时完成。如果你使用Big-O notation分析复杂度,你的算法是O(nq)
,对于这个问题来说太慢了,因为n*q
很大。
你应该做的是在进行任何查询之前计算分数,然后存储在一个数组中(这就是给出A[i]
的范围的原因。你应该能够通过遍历数组来做到这一点只有一次。(提示:您不需要将输入存储到数组中,直接计数即可)。
通过这样做,算法将只是O(n)
,并且由于n
足够小(根据经验,小于一百万是小的),它应该及时完成。
然后您可以立即回答每个查询,从而使您的程序足够快以达到时间限制。
您可以改进的另一件事是数组的数据类型。存储在该数组中的值不会大于 100 万,因此您不需要使用更多内存的 long long
。你可以使用int
。
【讨论】:
我可以用向量代替数组吗? @user2295715:当然,您需要随机访问。这是由std::deque
和std::vector
提供的,而不是由std::list
提供的。【参考方案2】:
您的算法效率低下。您将所有数字读入一个数组,然后在数组中线性搜索每个查询。
你应该做的是做一组计数。换句话说,如果您阅读数字 5,请执行 count[5]++。然后对于每个查询,您所要做的就是从数组中返回计数。例如,数组中有多少个 5?答案:count[5]。
【讨论】:
【参考方案3】:由于您的最大数量可以是 10^6,我认为您的问题将超出内存限制,即使它及时合适。另一种解决方案是对数组进行排序(您可以使用 STL 排序函数在 N*logN 中进行排序),并且对于每个查询,您可以进行两次二进制搜索。第一个用于查找元素出现的第一个位置,第二个用于查找元素出现的最后一个位置,因此每个查询的答案将是 lastPosition - firstPosition + 1。
【讨论】:
以上是关于处理大型数组时超出时间限制的主要内容,如果未能解决你的问题,请参考以下文章