求N!阶乘中结尾0的个数,或结果的二进制表示中最后一个1所在的位置

来源:互联网 发布:淘宝上飞机杯怎么样 编辑:程序博客网 时间:2024/05/28 15:06

问题1:阶乘结尾0的个数

要想阶乘的结尾是0,那么这个0已经通过5的倍数乘以另一个数获得,例如:5,10,15,20,25...,同时可以注意到这样一个规律,5,10,15,20,30,35,40与某个数相乘后可以贡献1个0,而25,50,75,100...与某个数相乘可以贡献2个0,5^3, 2* 5^3, 3*5^3与某个数相乘时贡献了3个0,依次类推。同时我们注意到,在统计5,10,15,20,25...时已经统计了一次25,50,75, 100,5^3, 2* 5^3, 3* 5^3一次了,而在统计25、50、75...时也统计了一次5^3, 2* 5^3...一次了,这样最终0的个数就是计算5的倍数出现了多少次+ 25的倍数出现了多少次 + 5^3出现了多少次,知道5^x > N,据此分析程序如下,如NumberOfZero1所示,

#include <stdio.h>int NumberOfZero(int var) {  int num = 0;  int j;  for (int i = 1; i <= var; ++i) {    j = i;    while (j % 5 == 0) {      num++;      j /= 5;    }  }  return num;}int NumberOfZero1(int var) {  int num = 0;  int base = 1;  int i = 1;  while (true) {    base = base * 5;    if (base > var) {      break;    }    i = 1;    while (base * i <= var) {      num++;      i++;    }  }  return num;}int main(int argc, char** argv) {  printf("method1: num = %d\n", NumberOfZero(14000));  printf("method2: num = %d\n", NumberOfZero1(14000));}

NumberOfZero是编程之美中给出了另一种求5、25、 5^3、个数的另一中求法,更加简洁一些。

问题2:二进制表示中最后一个1所在的位置

根据二进制数的性质,如果最后一位是1,那么该数为奇数,因为如果结尾为0,那么这个二进制数一定为偶数,因为结尾为0的数可以看作某个结尾为1的数,左移1位得到,即乘2后得到的数,因此一定是偶数,那么这个偶数再加1后,一定为奇数。

相似的分析,如果倒数第2位为1一定是2的倍数

如果倒数第3位是1一定是4的倍数

...

如果与问题1类比,如果N!有多少个2的倍数,相当于左移了多少位,相当于问题1的有多少个0,有多少个4的倍数,相当多少个左移2位,相当于问题1的贡献2个0...

同时注意到除了1!外,没有一个数的阶层是奇数,因为2以上的阶乘至少含有一个2这个因子。

因此问题2其实和问题1是相同的问题。

程序如下:

#include <stdio.h>int PositionOf1(int var) {  int pos = 0;  while (var) {    var>>=1;    pos += var;  }  return pos;}int PositionOf1_1(int var) {  int pos = 0;  int base = 1;  int i = 0;  while (true) {    base *=2;    if (base > var) {      break;    }    i = 1;    while (base * i <= var) {      pos++;      i++;              }  }  return pos;}int main(int argc, char** argv) {  printf("method1: num = %d\n", PositionOf1_1(14));  printf("method2: num = %d\n", PositionOf1(14));}

参考文献

编程之美p125 2.2

原创粉丝点击