阶乘(Factorial)是个很有意思的函数,但是不少人都比较怕它,我们来看看两个与阶乘相关的问题:

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

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

有些人碰到这样的题目会想:是不是要完整计算出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相乘可以得到一个10,于是M = min(X, Z)。不难看出X大于等于Z,因为能被2整除的数出现的频率比能被5整除的数高得多,所以把公式简化为M = Z。

根据上面的分析,只要计算出Z的值,就可以得到N!末尾0的个数。

【问题1的解法一】

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

ret = 0;
for(i = 1; i <= N; i++)
{ j = i; while(j % 5 ==0) { ret++;     //统计N的阶乘中那些能够被5整除的因子的个数j /= 5; }
}

【问题1的解法二】

公式:Z = [N/5] +[N/5^2] +[N/5^3] + …(不用担心这会是一个无穷的运算,因为总存在一个K,使得5^K > N,[N/5^K]=0。)

公式中,[N/5]表示不大于N的数中5的倍数贡献一个5,[N/5^2]表示不大于N的数中5^2的倍数再贡献一个5,……代码如下:

ret = 0;
while(N)
{ret += N / 5; N /= 5;
}

问题2要求的是N!的二进制表示中最低位1的位置。给定一个整数N,求N!二进制表示的最低位1在第几位?例如:给定N = 3,N!= 6,那么N!的二进制表示(1 010)的最低位1在第二位。

为了得到更好的解法,首先要对题目进行一下转化。

首先来看一下一个二进制数除以2的计算过程和结果是怎样的。

把一个二进制数除以2,实际过程如下:

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

所以,这个问题实际上等同于求N!含有质因数2的个数+1。即答案等于N!含有质因数2的个数加1。 实际上N!都为偶数,因为质因数里面都有一个2,除了1以外,因为1的阶乘是1,是个奇数,其他数的阶乘都是偶数。。

【问题2的解法一】

由于N! 中含有质因数2的个数,等于 N/2 + N/4 + N/8 + N/16 + …[1],

根据上述分析,得到具体算法,如下所示:

/*
可以先求出N!中2的个数(因为每存在一个2,则在数的
最低位多1个0)。因此求1的最低位的位置即为N!中2的个数+1;
*/
int lowestOnePos(int n)
{
int ret = 0;     //统计n!中含有质因数2的个数
while(n)
{
n >>= 1;
ret += n;
}
return ret+1;
}

【问题2的解法二】

N!含有质因数2的个数,还等于N减去N的二进制表示中1的数目。我们还可以通过这个规律来求解。

下面对这个规律进行举例说明,假设 N = 11011,那么N!中含有质因数2的个数为 N/2 + N/4 + N/8 + N/16 + …

即: 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的个数

小结
任意一个长度为m的二进制数N可以表示为N = b[1] + b[2] * 2 + b[3] * 22 + … + b[m] * 2(m-1),其中b [ i ]表示此二进制数第i位上的数字(1或0)。所以,若最低位b[1]为1,则说明N为奇数;反之为偶数,将其除以2,即等于将整个二进制数向低位移一位。

相关题目
给定整数n,判断它是否为2的方幂(解答提示:n>0&&((n&(n-1))==0))。

--------------------------------------------------------------------------------

[1] 这个规律请读者自己证明(提示N/k,等于1, 2, 3, …, N中能被k整除的数的个数)。

程序员面试100题之八:不要被阶乘吓倒(二进制表示中最低位1的位置 )相关推荐

  1. 程序员面试100题之七:最长公共子字符串

    子字符串的定义和子序列的定义类似,但要求是连续分布在其他字符串中.比如输入两个字符串BDCABA和ABCBDAB的最长公共字符串有BD和AB,它们的长度都是2. 最长公共子字符串共有两种解决方法,下面 ...

  2. 程序员面试100题之七 最长公共子字符串

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 子字符串 ...

  3. 程序员面试100题之六:最长公共子序列

           题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串.注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中.请编写一个函数,输 ...

  4. 程序员面试100题之六 最长公共子序列

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴!      ...

  5. 程序员面试100题之十五:数组分割

    一.题目概述:有一个没有排序,元素个数为2N的正整数数组.要求把它分割为元素个数为N的两个数组,并使两个子数组的和最接近. 假设数组A[1..2N]所有元素的和是SUM.模仿动态规划解0-1背包问题的 ...

  6. 程序员面试100题之十二:求数组中最长递增子序列

    写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中最长递增子序列的长度. 例如:在序列1,-1,2,-3,4,-5,6,-7中,其最长递增子序列为1,2,4,6. 分析与解法 根据题目要求, ...

  7. 程序员面试100题之十四:强大的和谐

    实现一个挺高级的字符匹配算法: 给一串很长字符串,要求找到符合要求的字符串,例如目的串:123 1******3***2 ,12*****3 这些都要找出来,其实就是类似一些和谐系统..... 这题的 ...

  8. 程序员面试100题之十三:求二叉查找树的镜像

    题目:输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点.用递归和循环两种方法完成树的镜像转换. 例如输入:      8 / \ 6   10 /\  ...

  9. 程序员面试100题之十:快速寻找满足条件的两个数

    能否快速找出一个数组中的两个数字,让这两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定存在至少一组符合要求的解. 假如有如下的两个数组,如图所示: 5,6,1,4,7,9,8 给定S ...

最新文章

  1. LeetCode 264. Ugly Number II--C++,Python解法
  2. 我的学习之路_第二十三章_HTML
  3. 【Hadoop】MapReduce笔记(二):MapReduce容错,任务失败处理
  4. 静物摄影用光技巧_室内人像摄影想要拍好,这3种用光技巧你了解吗?
  5. UnicodeDecodeError(转)
  6. solaris oracle 磁盘阵列,RAID-1 和 RAID-0 卷要求和原则
  7. 基于Flask开发网站--利用复选框进行批量操作
  8. 如何才能轻松地分析日志?
  9. 权限细粒度管理(转)
  10. 释放pytorch占用的gpu显存_pytorch程序异常后删除占用的显存操作
  11. rs232接口_USB转RS232接口9针串口线,工控数据转接线驱动安装方法
  12. emlog插件,emlog采集插件,emlog伪原创发布插件
  13. Thinkphp仿众图网图片素材下载站源码+自适应手机端
  14. QQ自动播放动态视频json卡片怎么换地址
  15. linux卸载LILO命令,Linux lilo命令
  16. 在Excel中如何让文字竖排
  17. So Who's Counting? by Erin McHugh and Emily Luchetti
  18. 微信里iphone后退不刷新问题解决方案,真实有效
  19. 参加软件测试培训找工作有前景吗
  20. windows media 服务器运行失败,Windows Media Player出现服务器运行失败怎么办?出现服务器运行失败处理方法介绍...

热门文章

  1. 怎样将1900-01-00变成-_《转生成蜘蛛又怎样》第2集预告:人类到来,蜘蛛子遭遇大危机...
  2. Gartner APM 魔力象限技术解读——全量存储? No! 按需存储?YES!
  3. Arthas 使用的四种方式
  4. AnalyticDB MySQL拥抱云原生,强力支撑双十一
  5. mysql事务操作——transaction
  6. Resin 的 watchdog(看门狗)介绍
  7. 表的连接方式:NESTED LOOP、HASH JOIN、SORT MERGE JOIN
  8. tomcat 相关以及安装时遇到的一些问题整理
  9. 【LeetCode 剑指offer刷题】回溯法与暴力枚举法题6:Number of Islands
  10. ASP.NET Core 实战:使用 NLog 将日志信息记录到 MongoDB