NowCoder猜想---统计n以内的素数个数
来源:互联网 发布:少年班人物原型知乎 编辑:程序博客网 时间:2024/05/16 15:17
题目描述
nowcoder在家极度无聊,于是找了张纸开始统计素数的个数。
设函数f(n)返回从1-n之间素数的个数。
nowcoder 发现:
f(1) = 0
f(10) = 4
f(100) = 25
...
满足g(m) = 17 * m^2 / 3 - 22 * m / 3 + 5 / 3
其中m为n的位数。
他很激动,是不是自己发现了素数分布的规律了!
请你设计一个程序,求出f(n),来验证nowcoder是不是正确的,也许还可以得诺贝尔奖呢。^_^
以上就是第一种,最直接的想法实现的代码。根据实际测试,这个代码是可以运行的。但是,跑程序是讲究效率的,OJ是有时间限制的,
这个函数放到程序中运行,可以在1秒中之内计算完10^7以内素数的个数。速度还是满足要求的。成功通过了OJ测试。O(∩_∩)O~
设函数f(n)返回从1-n之间素数的个数。
nowcoder 发现:
f(1) = 0
f(10) = 4
f(100) = 25
...
满足g(m) = 17 * m^2 / 3 - 22 * m / 3 + 5 / 3
其中m为n的位数。
他很激动,是不是自己发现了素数分布的规律了!
请你设计一个程序,求出f(n),来验证nowcoder是不是正确的,也许还可以得诺贝尔奖呢。^_^
输入描述:
输入包括多组数据。每组数据仅有一个整数n (1≤n≤10000000)。
输出描述:
对于每组数据输入,输出一行,为1->n(包括n)之间的素数的个数。
输入例子:
110651000
输出例子:
041825
--------------------------我是华丽的分割线-------------------------------------------------
这道题其实很简单,会判断素数,会统计个数,再写个循环就可以啦。
所以第一种,也是最容易想到的做法就是,循环从1< i <= n, 循环中加上判断i是否为素数,是则计数+1,否则不加
代码实现如下:
这道题其实很简单,会判断素数,会统计个数,再写个循环就可以啦。
所以第一种,也是最容易想到的做法就是,循环从1< i <= n, 循环中加上判断i是否为素数,是则计数+1,否则不加
代码实现如下:
</pre><pre name="code" class="cpp">#include <stdio.h>#include <stdlib.h>#include <math.h>#include <time.h>int is_prime(int n){ int i = 2; if (n < 2) { return 0; } while (i <= sqrt(n)) { if (n%i == 0) { return 0; } i++; } return 1;}int prime(int n){ int cnt = 0; int i = 0; for (i = 2; i <= n; i++)// += 2) { if(is_prime(i)) { cnt++; } } return cnt;}int main(){ int n = 0; int cnt = 0; clock_t st, en; while (1) { scanf("%d", &n); if (n == 0) { break; } cnt = prime(n); printf("%d\n", cnt); } return 0;}
以上就是第一种,最直接的想法实现的代码。根据实际测试,这个代码是可以运行的。但是,跑程序是讲究效率的,OJ是有时间限制的,
当n=1000 000 时,这个程序的速度就很慢了,更不用提n=10 000 000的时候了。
因此我们就需要对这个程序进行改进。首先我想到的是,既然是素数,那么偶数肯定就不是素数啦,这是很明显的。但是上面的程序也对偶数进行了判断,因此这里的时间浪费了不少(毕竟偶数个数占了一半呢!)。然后我又想,偶数是2的倍数,那么3、5、7、11的倍数也不可能是素数,这样素数判断的次数就会减少不少了。
int is_prime(int n){ int i = 2; if (n < 2) { return 0; } if (n == 2 || n == 3 || n == 5 || n == 7 || n == 11) return 1; if (n%2 == 0 || n%3 == 0 || n%5 == 0 || n%7 == 0 || n%11 == 0) return 0; while (i <= sqrt(n)) { if (n%i == 0) { return 0; } i++; } return 1;}int prime(int n){ int cnt = 0; int i = 0; if (n >= 2) cnt++; for (i = 3; i <= n; i += 2) { if(is_prime(i)) { cnt++; } } return cnt;}
prime()和is_prime()这个两个函数修改之后,程序的运行速度提升并没有想象的多,因此还需继续想办法。。。。
然后我发现我想不动了 /(ㄒoㄒ)/~~于是就各种google,各种百度看看别人怎么做,然后就通过这篇博客http://blog.csdn.net/code_pang/article/details/7880245发现了一个有趣的结论。
对于大于等于5的素数素数只可能是6n-1或者6n+1,因此,这样就可以加快素数的判断了。于是我写了一个新的函数is_prime1()
根据测试结果可以知道,当n=10^6时,运行结果瞬间就出来了,但是当n=10^7时,结果还是需要数秒钟才能出来。因此还是没有通过OJ/(ㄒoㄒ)/~~
int is_prime1(int n){ int i = 0; if (n == 2 || n == 3 || n == 5 || n == 7 || n == 11) { return 1; } if (n%3 == 0 || n%5 == 0 || n%7 == 0 || n%11 == 0) { return 0; } if (n%6 != 1 && n%6 != 5) { return 0; } for (i = 5; i*i <= n; i+= 6) { if (n%i == 0 || n%(i+2) == 0) { return 0; } } return 1;}
根据测试结果可以知道,当n=10^6时,运行结果瞬间就出来了,但是当n=10^7时,结果还是需要数秒钟才能出来。因此还是没有通过OJ/(ㄒoㄒ)/~~
因此还是必须继续寻找更快的方式。
此时,删选法出现了,百度百科有相关的解释http://baike.baidu.com/view/2722688.htm,有兴趣的可以去看看。
由于某博客博主的代码注释和详细,因此我就直接复制过来,但是由于写这篇博客的时候,我已经找不到这个代码片作者的那个博客了,无法提供链接。如果此作者看到了,可以给我留言,要求我删除或者注明改代码的引用都是可以的:-D
int CompositeNumFilterV2(int n){ if(n==1) { return 0; } int i, j; // 素数数量统计 int count = 0; // 分配素数标记空间,明白+1原因了吧,因为浪费了一个flag[0] bool* flag = new bool[n+1]; //这个要是用int* flag=new int[n+1],就会溢出,因为int占4bit,则4*1000000000=4M左右的内存,而用bool或者char,则少得多 // 初始化素数标记,要高效点咯 flag[2]=1; // 注意是i<n不是上例中的i<=n了 for (i=3; i<n; i++) { //flag[i]=(i%2!=0)?1:0;//偶数直接值0,奇数值1,2特殊处理,但是这个有判断操作,效率肯定没有直接赋值快,所以用下面的 flag[i++]=1; flag[i]=0; } // n为奇数 if (n%2 != 0) { flag[n] = 1; } // 从3开始filter,因为2的倍数早在初始化时代就干掉了 for (i=3; i <= sqrt((double)n); i++) { // i是合数,请歇着吧,因为您的工作早有您的质因子代劳了 if (0 == flag[i]) continue; // 从i的平方倍开始过滤,而不是从前面的已经被其他素数筛掉了,另外变乘法为加法,加法效率比乘法快 for (j=i*i; j <= n; j+=i) { flag[j] = 0; } } // 统计素数个数 for (i=2; i<=n; i++) { if (flag[i]) count++; } // 释放内存,别忘了传说中的内存泄漏 delete[] flag; return count;}
这个函数放到程序中运行,可以在1秒中之内计算完10^7以内素数的个数。速度还是满足要求的。成功通过了OJ测试。O(∩_∩)O~
其实也可以看到此函数在实现素数统计的过程中其算法的复杂度是O(n)的,而之前我的做法是O(n^2)的。所以当n比较大的时候,速度肯定会慢不少的。
最后,在搜索这个编程题更好解法的过程中,我发现有位网友http://www.2cto.com/kf/201303/194987.html 提供了一个算法,号称百亿内3毫秒解决,我看了一会儿没看懂,就没继续研究。。。我承认我还是很懒的。。。
1 0
- NowCoder猜想---统计n以内的素数个数
- 求n以内的素数个数问题
- hdu 5901 Count primes(Meisell-Lehmer 统计n(很大)以内的素数个数)
- 求N以内的所有素数的个数
- 求N以内的素数。
- 用筛法求N以内的素数
- 素数的个数统计
- (java)统计小于N的数中素数的个数
- Java-NowCoder-字符个数统计
- 计算100以内的素数的个数
- 求一千万以内的素数的个数
- 求100以内的素数以及个数
- 求1e11以内的素数个数
- HDU5901 1e11以内素数的个数
- 筛选求n以内素数并返回个数
- 求N以内素数个数--粗暴方式及筛选法
- 求素数,给你一个n,输出n以内的素数
- 快速找出N以内的素数
- 1153 选择子序列
- Mysql数据库备份和还原常用的命令
- 机器学习一些博客
- hello, world
- JavaScript之this用法详解
- NowCoder猜想---统计n以内的素数个数
- mysql中为用户设置密码的多种方法
- Yii2学习笔记(一):Yii的安装和使用
- TabLayout、ViewPager和Fragment的多页面滑动
- 程序烧写(使用SEGGER)
- 解决Linux MySQL报错ERROR 2002
- nyoj 189 兔子的烦恼(一)(辗转相除法求最大公约数)
- K-Nearest Neighbors algorithm
- iOS中内存初级管理