问题的链接 - https://www.hackerrank.com/contests/freshers-challenge-2/challenges/counting-the-steps
问题如下 - 找出a和b之间的素数(包括a和b,以防它们是素数。)
我使用了Eratosthenes的筛子来解决问题,但我在两个测试用例上超时。
特别是对于一个有10,000个数字的测试用例,我的C ++程序在CodeBLocks中花了大约10秒钟。我正在下面插入代码片段 -
for(int i=2;i<=upperbound;i++)
{
prime[i-2]=i;
}
int sq=sqrt(upperbound);
for(int i=0;prime[i]<=sq;i++)
{
if(prime[i]!=0)
{
int j=i+prime[i];
for(;j<m;j+=prime[i])
{
prime[j]=0;
}
}
}
这是筛子的代码片段。我的输出都是正确的,但我怎样才能使这个程序更快。
编辑:在用sq
替换upperbound之后解决了分段错误答案 0 :(得分:2)
您正在使用 sqrt
,这可能非常耗时,尤其是在找到双根时。之后你甚至都不使用sq
。
修改:尝试在循环中将upperbound
替换为sq
。它会解决一些速度问题,但不会解决因分配太大内存而导致的段错误。
筛选算法的问题在于它为所有数字分配完整数组。
查找素数的另一种方法是通过将它们除以素数来检查所有数字,直到它们的平方根。对该算法的简单优化是避免偶数。并将仅存储结构中的素数。
int lastBound = 0; //avoids doing too many multiplications
vector<int> primes;
primes.push_back(2);
for (int i = 3; i <= upperbound; i+= 2) {
bool prime = true;
for(int j : primes) {
if (j > lastBound && j * j > i) {
lastBound = j;
break;
}
if (i%j == 0) {
prime = false;
break;
}
}
if (prime) {
primes.push_back(i);
}
}
然后你在列表中有素数,你可以将它转换成你拥有的数组,集合或其他任何数据。
有些动态分配可能会导致一些延迟,但对于大小为vector
的{{1}},只有O(log(n))分配。可能会有进一步的优化,但为了你的目的,它应该足够了。
答案 1 :(得分:0)
我在代码中看到的吞咽者唯一一次使用sqrt
。
您可以使用digit by digit method in base 2。
但这是一个小改进。
您必须更改算法才能获得更好的效果。 搜索素数是一个难题,并且有很多最差解决方案(例如,您可以使用pseudo-prime filters ...)
答案 2 :(得分:0)
您有效地在数组中存储两次素数。 prime[i] == i+2
,因此您可以将int j=i+prime[i];
替换为int j=i+(i+2);
。
现在,如果您不再需要实际值,则只能存储一个位:std::vector<bool> prime(upperbound, true);
。这减少了95%(可能)所需的内存,这使得你的筛子很可能适合CPU缓存。
在prime
的开头保存2位是一个坏主意。其他地方的单个i-2
指令将至少占用整个字节,并且还会花费您实际的运行时间。