【编程之美学习笔记】2.2不要被阶乘吓到

我好饿吖, 为什么我现在在教室闻到了饭香味。。。

问题1.给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N=3 628 800, N!的末尾有两个0。

(好巧吖,昨天做的51nod 1003就是这个题,来分析一下吧!)

看到这题,你想完整计算N!的值吗?那可能溢出哦。其实这个问题只要从“哪些数相乘能得到10”这个角度考虑就简单啦。

首先,如果N!=k * 10^M, 且K不能被10整除,那么N!的末尾有M个0。再对N!进行质因数分解,N!=(2^X)*(3^Y)*(5^Z)…,因为10=2*5,所以M只与X和Z有关,又因为能被2整除的数出现的概率比能被5整除的数高得多,所以M = Z。

解法一:

最直接的方法就是计算i(i = 1,2…N)的因式分解中5的指数,然后求和。

 1 int Count0(int n){
 2     int num = 0;
 3     int i, j;
 4     for(i = 1;i <= n;++i){
 5         j = i;
 6         while(j % 5 == 0){
 7             num++;
 8             j /= 5;
 9         }
10     }
11     return num;
12 }

解法二:

公式:Z=[N/5] + [N/(5^2)] + [N/(5^3)] + …   公式中[N/5]表示不大于N的数中5的倍数贡献一个5,[N/(5^2)]表示不大于N的数中5^2的倍数再贡献一个5.

1 int Count0(int n){
2     int num = 0;
3     while(n){
4         num += n / 5;
5         n /= 5;
6     }
7     return num;
8 }

问题2.求N!的二进制表示中最低位1的位置。

为了得到更好的解法,要对题目进行转化,首先看一个二进制数除以2的计算过程和结果是怎样的。

判断最后一个二进制位是否为0:若为0,则将此二进制数右移一位,即为商值;反之,若为1,则说明这个二进制数是奇数,无法被2整除。

所以这个问题实际上等同于求N!含有质因数2的个数。即答案等于N!含有质因数2的个数加1。

解法一:

公式:X = [N/2] + [N/4] + [N/8] + [N/16] + …

1 int lowestOne(int n){
2     int num = 0;
3     while(n){
4         n >>= 1;
5         num += n;
6     }
7     return num + 1;
8 }

解法二:

有规律:N!含有质因数2的个数,还等于N减去N的二进制表示中1的数目。

下面对这个规律举例说明:

假设N = 11011(二进制表示,下列01串均为整数的二进制表示),那么N!中含有质因数2的个数为:

   1101 + 110 +11 + 1

= (1000 + 100 + 1) + (100 +10) + (10 + 1) + 1

= (1000 + 100 + 10 + 1) + (100 + 10 + 1) + 1

= 1111 + 111 + 1

= (10000 - 1) + (1000 - 1) + (10 -1) + (1 - 1)

= 11011  - (N二进制表示中1的个数)

很巧吧!

1 int lowestOne(int n){
2     int num = 0;
3     int t = n;
4     while(t){
5         t &= (t-1);
6         num++;
7     }
8     return n - num + 1;
9 }

时间: 2024-11-05 13:26:16

【编程之美学习笔记】2.2不要被阶乘吓到的相关文章

编程之美学习笔记(一)-让CPU占用率曲线听你指挥

终于放假了,开始在家里看一本向同学借来被程序猿尊称的必看经典书之一---<编程之美>.这本书给我的第一感觉是,他不单单是一本介绍算法的书,更不是一本纯算法的书,更多的是跟生活的很多实际问题息息相关,让你能更多地思考当我们面对现实实际问题的时候如何用自己从之前书本学习到的理论的知识去解决他们,如何以理论联系实际.这个寒假都会更新从这本书中学习来的知识,也希望有相同兴趣的人可以一起共同交流.那么就开始进入正题吧. 如何让cpu占用率呈现直线或者正弦曲线呢,看完第一章节,最简单的无非是调整自己写的程

编程之美学习笔记之 一摞烙饼的排序

编程之美书中讲的一摞烙饼的排序一题 这里无法用基本的排序方法对其排序,那么最直接的方法是找出N个数种最大者,将这通过两次翻转放置到最底部,然后处理N-1,N-2等,直到全部排序完,所以一共需要交换2(N-1)次 void reverse(int cakes[], int beg, int end) { int temp; while(beg < end){ temp = cakes[beg]; cakes[beg++] = cakes[end]; cakes[end--] = temp; } }

【编程之美学习笔记】2.1求二进制数中1的个数

问题:对于一个字节(8bit)的无符号整型变量,求其二进制表示中“1”的个数,要求算法的执行效率尽可能高. 解法一:除.余操作 我们知道,对于二进制操作,除以一个2,原来的数字将会减少一个0,如果除的过程中有余,那么就表示当前位置有一个1,所以可通过相除和判断余数的值来分析. [时间复杂度O(log2v),log2v为二进制数的位数,空间复杂度O(1)] 1 int Count(int v){ 2 int num = 0; 3 while(v){ 4 if(v % 2 == 1) num++;

编程之美读书笔记1.8 - 小飞的电梯调度算法

http://blog.csdn.net/pipisorry/article/details/36688019 问题: 亚洲微软研究院所在的希格玛大厦一共有6部电梯.在高峰时间,每层都有人上下,电梯每层都停.实习生小飞常常会被每层都停的电梯弄的很不耐烦,于是他提出了这样一个办法: 由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层.所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层.在一楼的时候,每个乘客选择自己的目

《编程之美-读书笔记》-1 中国象棋将帅问题

时间:2014.05.27 地点:基地 ---------------------------------------------------------------------------------------- 一.指针和引用的区别 1.指针可以为空,引用不可以不空. 引用是一个对象的别用,定义一个引用时必须初始化,而声名指针时可以不指向任何对象,故使用指针时也常要做空的判断,而引用无需,因为引用总是绑定着一个对象. 2.指针可以改变指向,而引用不可以重新绑定新对象.(指针变异思迁,引用从

编程之美读书笔记1.2——中国象棋将帅问题

http://blog.csdn.net/pipisorry/article/details/36380669 问题:下过中国象棋的朋友都知道,双方的"将"和"帅"相隔遥远,并且它们不能照面.在象棋残局中,许多高手能利用这一规则走出精妙的杀招.假设棋盘上只有"将"和"帅"二子(如图1-3所示)(为了下面叙述方便,我们约定用A表示"将",B表示"帅"): A.B二子被限制在己方3×3的格子

shell编程教程or学习笔记

----------------------------------------------------hello world------------------------------------------- linux 创建如下文件 vim hello #! /bin/bash   //告诉Shell 使用哪个Shell 程序 #Display  a line    //#表示注释 //空白行用来区分不同更功能 没有实际意义 name="[email protected]" ec

《javascript DOM 编程艺术》学习笔记(一)

书籍已经看完了前六章的内容,有了一定的编程基础后觉得本书内容相对来说过于简单,应该是完全针对于初学者的(或者如作者所说是写个Web设计师的),作者在表述一个问题,一句代码都解释得非常啰嗦与重复,不过从书中学习到更多的,也是作者想让读者体会的是让大家理解DOM脚本编程技术背后的思路和原则,作者特别以早期Javascript的滥用来强调Web的规范与标准,这一点是非常值得学习的,也是一个程序员的基本素养. 截止到第六章,将所学到的知识点归纳如下: 1.基本语法:与php一样是弱类型语言,虽然功能强大

编程之美读书笔记2.15 - 子数组之和的最大值(二维)

http://blog.csdn.net/pipisorry/article/details/39083073 问题: 求二维数组(矩阵)的子矩阵之和的最大值. 亦可见:http://poj.org/problem?id=1050 解法1:(解释见注释) 每个子矩阵由列长.行长和左上角的元素位置决定.如果我们指定左上角的元素位置 (i,j) 和列长 c,那么可以求所有这些子矩阵中和最大的.然后,变化列长 c,可以求以 (i,j) 为左上角的最大和子矩阵.最所有左上角位置再求最大和子矩阵,问题就解