阶乘相关问题

 定义:
      一个正整数的阶乘(英语: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的位数
  * @param N 求阶乘的数
  * @return N的阶乘结果末尾0的位数
  */
 public static int getLowZeroNum(int N)
 {
  int ret = 0;
  int j ;
  for(int i = 1 ; i <=N ; i++)
  {
   j = i;
   while(j % 5 == 0)
   {
    ret ++;
    j = j / 5;
   }
  }
  return ret;
 }
方法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的位数
  * @param N 求阶乘的数
  * @return N的阶乘结果末尾0的位数
  */
 public static int getLowZeroNum2(int N)
 {
  int ret = 0;
  while(0 != N)
  {
   ret += N/5;
   N /= 5;
  }
  return ret;
 }


 
问题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的位置
  * @param N 求阶乘的数
  * @return N的阶乘最低位1的位置
  */
 public static int getThePosition(int N)
 {
  int ret = 0;
  while(0 != N)
  {
   N = N >> 1; //右移一位,相当于十进制除以2
 
   ret += N; //不大于当前N的2的倍数的个数
  }
  return ret;
 }

 
测试:
public static void main(String[] args)
 {
  //测试计算N的阶乘结果末尾0的位数
  int N = 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的位数:1
5的阶乘结果末尾0的位数:1
5N的阶乘最低位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,即等于将整个二进制数向低位移一位。 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/0201zcr/p/4637492.html