定义: 一个正整数的阶乘(英语:factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1。自然数n的阶乘写作n!。 亦即n!=1×2×3×...×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。 问题1、给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N = 10 , N! = 3628800,N!的末尾有两个0。 解析:加入完整得计算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(能整除的5的个数); 方法1: 最直接的方法,计算i(1,2,3,……,N)的因式分解中5的指数,然后求和。/*** 计算N的阶乘结果末尾0的位数*@paramN 求阶乘的数*@returnN的阶乘结果末尾0的位数*/publicstaticintgetLowZeroNum(intN){intret = 0;intj ;for(inti = 1 ; i <=N ; i++){j=i;while(j % 5 == 0){ret++;j= j / 5;}}returnret;} 方法2:公式法 公式:Z = 【N/5】 + 【N/5的平方】 + 【N/5的立方】+……, (不用担心这回事一个无穷的运算,因为总存在一个K,使得 5的K次方 > N,【N/5的K次方】 = 0。 公式中,【N/5】表示不大于N的数中5的倍数贡献一个5,【N/5的平方】表示不大于N的数中,5的平凡的倍数在贡献一个5…… 代码如下:/*** 计算N的阶乘结果末尾0的位数*@paramN 求阶乘的数*@returnN的阶乘结果末尾0的位数*/publicstaticintgetLowZeroNum2(intN){intret = 0;while(0 !=N){ret+= N/5;N/= 5;}returnret;} 问题2、求N!的二进制表示中最低位1的位置 把一个2进制数除以2,判断最后一个二进制位是否为0;若为0,则将此二进制数右移一位,即为商值;反之,若为1,则说明这个二进制数是奇数,无法被2整除。所以这个问题实际上等同于求N!含有质因数2的个数。即答案等于N!含有质因数2的个数加1。 解法1: N!中含有质因数2的个数,等于【N/2】+【N/4】+【N/8】+【N/16】+ ……,具体算法如下:/*** N的阶乘最低位1的位置*@paramN 求阶乘的数*@returnN的阶乘最低位1的位置*/publicstaticintgetThePosition(intN){intret = 0;while(0 !=N){N= N >> 1;//右移一位,相当于十进制除以2ret+= N;//不大于当前N的2的倍数的个数}returnret;} 测试:publicstaticvoidmain(String[] args){//测试计算N的阶乘结果末尾0的位数intN = 5;System.out.println(N+ "的阶乘结果末尾0的位数:" +Factorial.getLowZeroNum(N));System.out.println(N+ "的阶乘结果末尾0的位数:" +Factorial.getLowZeroNum2(N));//测试N的阶乘最低位1的位置System.out.println(N + "N的阶乘最低位1的位置:" +Factorial.getThePosition(N));} 结果:5的阶乘结果末尾0的位数:15的阶乘结果末尾0的位数:15N的阶乘最低位1的位置:3 小结: 任意一个长度为m的二进制数N可以表示为 N = b[1] + b[2]*2 + b[3]*4 + …… + b[m]*2的m-1次方 ,其中b[i]表示此二进制数第i位上的数字(1或0)。所以,若最低位b[1]为1,则说明N为奇数;反之为偶数,将其除以2,即等于将整个二进制数向低位移一位。 本文链接:阶乘相关问题,转载请注明。