今天遇到一个题,看起来很简单,实则有坑。
题目就是判断一个整数是否为素数(只能被1和它自己整除的整数)。我一开始的代码长这个样子:
bool isPrime(int num) {
if(num == 1)
{
return false;
}
if(num ==2)
{
return true;
}
for(int iter = 2;iter < num;++iter)
{
if(num % iter == 0)
{
return false;
}
}
return true;
}
然后点击test,通过。再点击attempt,报错如下。
上图的报错主要有两个问题,第一个问题暂时不管,第二问题很明显:时间复杂度太高(O(n))。
于是我上网找了方法,循环只进行到n的平方根,这样时间复杂度可以降低到O(sqrt(n)),代码如下:
bool isPrime(int num) {
if(num == 1)
{
return false;
}
if(num ==2)
{
return true;
}
for(int iter = 2;iter <= sqrt(num);++iter)
{
if(num % iter == 0)
{
return false;
}
}
return true;
}
attempt之后,第一个问题还是存在。上网找了一下,这个叫负面测试,意思是代码除了执行需要的功能外,还干了没有必要的事情。
后来发现还是因为循环不够简化,找到了素数的又一个规律,就是6以上的素数,都在6的整数倍的两侧,比如23在6的4倍的左侧,37在6的6倍的右侧。但又有些6的倍数的两侧的数不是素数,所以这是个充分不必要条件。于是再次简化代码如下:
using namespace std;
bool isPrime(int num) {
if(num == 1)
{
return false;
}
if(num == 2 || num == 3)
{
return true;
}
if(num % 6 != 1 && num % 6 != 5)
{
return false;
}
for(int iter = 2;iter <= sqrt(num);++iter)
{
if(num % iter == 0)
return false;
}
return true;
}
这次才把问题搞定。截图如下:
此时时间复杂度仍然为O(sqrt(n))。
总结:看似很简单的题目,也需要很认真地思考,设计精巧的算法,有时候还需要在网上找资料,才能通过。否则,就会像我这样,一步步接受素数的审判。