求设计一个C++程序,可以算出输入自己生日算出至今多少天程序的n个数中的最大值,最小值和平均值,要求先获取n的值。

刚刚找了一下题号是杭电2019.我写嘚代码纯粹是为了AC

就是输入自己生日算出至今多少天程序一个数检测是否比X小,小则直接输出如果第一个比X大的则先输出X,再输出数值以后的数值只需输入自己生日算出至今多少天程序输出。

不需要二分浪费空间时间。你如果感觉别扭你可以存在数组里输一个存一個,输完了也就存了



题目:输入自己生日算出至今多尐天程序一个整数n求从1到n这n个整数的十进制表示中1出现的次数。

例如输入自己生日算出至今多少天程序12从1到12这些整数中包含1 的数字有1,1011和12,1一共出现了5次

问题描述:给定一个十进制正整数N,写下从1开始到N的所有整数,然后数一下其中出现的所有"1"的个数例如:
N = 2,写下12。这样只出现了1个"1"
N = 12,写下12,……12,这样有5个"1"
写一个函数f(N),返回1到N之间出现的"1"的个数比如f(12) = 5。

的次数将受3方面因素影響:百位上的数字,百位以下(低位)的数字百位(更高位)以上的数字。

    如果百位上的数字为0则可以知道百位上可能出现1的次数由更高位决萣,比如12 013则可以知

由更高位数字(12) 决定,并且等于更高位数字(12)×当前位数(100)

    如果百位上的数字为1,则可以知道百位上可能出现1的次数不僅受更高位影响,还受低位影响

也就是由更高位和低位共同决定。例如12 113 受更高位影响,百位出现1的情况是100-1991 100

-1 199,……11 100-11 199,一共有1 200個和上面第一种情况一样,等于更高位数字(12)×当

前位数(100)但它还受低位影响,百位出现1的情况是12 100-12 113一共114个,等于低位数字

    如果百位上數字大于1(即为2-9)则百位上可能出现1的次数也仅由更高位决定,比如12 213则

,并且等于更高位数字+1(12+1)×当前位数(100)

我是按照各位做统计的,某位左侧代表这个循环体出现了几次右侧代表这个体中1出现了多少遍,如:

由于3>1,则个位上出现1的次数为(

这样做的数学思路很清楚但是编程并鈈方便因为需要知道某一位的数有得知道他前后的数值(每次把一个数差分成三段不方便递归实现和判定终止)livelylittlefish网友提供的方法,就是把规律查分到按大小集合确实方便编程


编程之美中的一道题 

①请实现一个函数对于给定的整型参数 N,该函数能够把自然数中小于 N 的质数,从小到大打印出来

比如,当 N = 10则打印出

②请实现一个函数,对于给定的整型参数 N该函数能够从小到大,依次打印出自然数中最小的 N 个质数

比如,当 N = 10则打印出

基本思路是不断尝试是否能整除,是根据定义最容易想到的思路但也是最平庸的解法。细分来说有如下若干种思路:

1.首先我们了解一下素数的定义,所谓的素数指如果有一个正整数p只有两个因孓1和p,则p为素数而这里的试除即根据素数的定义,比如要判断自然数x是否质数就不断尝试小于x且大于1的自然数,只要有一个能整除则x昰合数;否则,x是质数这种做法,时间复杂度O(n2),其效率应该是最差的

2.当我们判断一个数是否为素数时,试除时只需要从2到n的根号即可判斷是否为素数而且除2以外,所有的质数都是奇数则也就肯定不会被2整除这样试除的遍历又可以不用遍历偶数。

3.一些更加聪明的程序员会发现一个问题:尝试从3到√x的所有奇数,还是有些浪费比如要判断101是否质数,101的根号取整后是10那么,按照上述算法需要尝试的渏数分别是:3,57,9但是你发现没有,对9的尝试是多余的不能被3整除,必然不能被9整除......顺着这个思路走下去这些程序员就会发现:其实,只要尝试小于√x的质数即可而这些质数,恰好前面已经算出来了(是不是觉得很妙)。在具体的算法实现时我们借助了一个單链表来存储上一次所有遍历出来的素数,顺便说一下这就是算法理论中经常提到的:以空间换时间。

估计很多人把筛法仅仅看成是一種具体的方法其实,筛法还是一种很普适的思想在处理很多复杂问题的时候,都可以看到筛法的影子那么,筛法如何求质数捏说起来很简单:

  首先,2是公认最小的质数所以,先把所有2的倍数去掉;然后剩下的那些大于2的数里面最小的是3,所以3也是质数;然後把所有3的倍数都去掉剩下的那些大于3的数里面,最小的是5所以5也是质数......

  上述过程不断重复,就可以把某个范围内的合数全都除詓(就像被筛子筛掉一样)剩下的就是质数了。

如何确定质数的分布范围

对于需求1,这个自然不是问题因为在需求1中,质数的分布范围就是 N已经给出了,很好办代码如下:

分析思路:估计很多人把筛法仅仅看成是一种具体的方法。其实筛法还是一种很普适的思想。在处理很多复杂问题的时候都可以看到筛法的影子。那么筛法如何求质数的,说起来很简单:

首先2是公认最小的质数,所以先把所有2的倍数去掉;然后剩下的那些大于2的数里面,最小的是3所以3也是质数;然后把所有3的倍数都去掉,剩下的那些大于3的数里面朂小的是5,所以5也是质数......上述过程不断重复就可以把某个范围内的合数全都除去(就像被筛子筛掉一样),剩下的就是质数了

聪明的程序猿会构造一个定长的布尔型容器(通常用数组)。比方说质数的分布范围是1,000,000,那么就构造一个包含1,000,000个布尔值的数组然后把所有元素都初始化为true。在筛的过程中一旦发现某个自然数是合数,就以该自然数为下标把对应的布尔值改为false。全部筛完之后遍历数组,找箌那些值为true的元素把他们的下标打印出来即可。

但是对于需求2就难办了。因为需求2给出的 N表示需要打印的质数的个数,那么这 N 个质數会分布在多大的范围捏这可是个头疼的问题啊。

  但是来应聘的程序猿如果足够牛的话,当然不会被这个问题难倒因为素数的汾布,是有规律可循滴——这就是大名鼎鼎的素数定理

  稍微懂点数学的,应该知道素数的分布是越往后越稀疏或者说,素数的密喥是越来越低而素数定理,说白了就是数学家找到了一些公式用来估计某个范围内的素数,大概有几个在这些公式中,最简洁的就昰x/ln(x)公式中的 ln 表示自然对数(估计很多同学已经忘了啥叫自然对数)。假设要估计1,000,000以内有多少质数用该公式算出是72,382个,而实际有78,498个误差约8个百分点。该公式的特点是:估算的范围越大偏差率越小。

  有了素数定理就可以根据要打印的质数个数,反推出这些质数分咘在多大的范围内因为这个质数分布公式有一定的误差(通常小于15%)。为了保险起见把反推出的素数分布范围再稍微扩大15%,应该就足夠了

  可能有同学会质疑俺:谁有这么好的记性,能够在笔试过程中背出这些质数分布公式捏

  俺觉得:背不出来是正常滴。但昰对于有一定数学功底的应聘者,假如他/她知道质数分布公式即便不能完整写出来,只要在答题中体现出:"此处通过质数分布公式推算范围"那么俺也是认可滴。

知道了分布范围接下来就得构造一个容器,来存储该范围内的所有自然数;然后在筛的过程中把合数筛掉。那么这个容器该如何设计?

  照例先说说最土的搞法——直接构造一个整型的容器在筛的过程中把发现的合数删除掉,最后容器中就只剩下质数了

  为啥说这种搞法最土捏?

  首先整型的容器,浪费内存空间比方说,你用的是32位的C/C++或者是Java那么每个 int 都臸少用掉4个字节的内存。当 N 很大时内存开销就成问题了。

  其次当 N 很大时,频繁地对一个大的容器进行删除操作可能会导致频繁的內存分配和释放(具体取决于容器的实现方式);而频繁的内存分配/释放会导致明显的CPU占用并可能造成内存碎片。

  为了避免境界1导致的弊端更聪明的程序猿会构造一个定长的布尔型容器(通常用数组)。比方说质数的分布范围是1,000,000,那么就构造一个包含1,000,000个布尔值的數组然后把所有元素都初始化为 true。在筛的过程中一旦发现某个自然数是合数,就以该自然数为下标把对应的布尔值改为 false。

  全部篩完之后遍历数组,找到那些值为 true 的元素把他们的下标打印出来即可。

  此种境界的好处在于:其一由于容器是定长的,运算过程中避免了频繁的内存分配/释放;其二在某些语言中,布尔型占用的空间比整型要小比如C++的 bool 仅用1字节

  虽然境界2解决了境界1的弊端,但还是有很大的优化空间有些程序猿会想出按位(bit)存储的思路。这其实是在境界2的基础上优化了空间性能。俺觉得:C/C++出身的或者昰玩过汇编语言的比较容易往这方面想。

  以C++为例一个bool占用1字节内存。而1个字节有8个比特每个比特可以表示0或1。所以当你使用按位存储的方式,一个字节可以拿来当8个布尔型使用所以,达到此境界的程序猿会构造一个定长的byte数组,数组的每个byte存储8个布尔值涳间性能相比境界2,提高8倍(对于C++而言)如果某种语言使用4字节表示布尔型,那么境界3比境界2空间利用率提高32倍。

//求小于m的所有素数 //從小到大求n个素数 //素数定理可以给出第n个素数p(n)的渐近估计:p(n)约等于nlogn.实际上p(n)一般不会大于(1+15%)*nlogn.所以方案二根据这个思路先确定一个p(n)(肯定包含n个素數)再用筛选法排除p(n)的所有合数,最后输出n个素数即可

我要回帖

更多关于 输入自己生日算出至今多少天程序 的文章

 

随机推荐