《编程之美》读书笔记(三)——阶乘结果末尾"0"的个数

对于第一个问题,我起初的思路如下:
     能贡献末尾“0”的数有两类,一类是自身以“0”结尾,例如,10,560,1000等,另一类是个位数是2和5相乘得到。因为是阶乘,从1到N,所以对于每个个位为5的数,总能找到一个其他位相同个位为2的数与之匹配。所以,只需要去数[1,N]中以“0”结尾的数总共多少个“0”,再加上N/10+(N%10<5?0:1)【个位数为5的数的个数】。
     从1到N,出现“0”结尾次数为N/10;出现"00"结尾次数为N/100【个位上的“0”已经被记录,此处不记】;...,因此,第一类数含"0"总数为(N/10+N/100+N/1000+...)

     这种思路是错误的!!错的原因在于个位为5的数可能可以产生多余1个“0”,譬如25*4=100,而上述思路只计1个“0”,因此结果偏小。
     
看来还是书上给的思路比较好。

问题转化(简化):
书上最开始是对问题进行转化,首先,分析结尾的“0”是由因子2和5相乘得到,进而考虑对N!进行因式分解,考察其中因子2和5的个数,结尾“0”的个数等于Min(#(2),#(5)),直观地可知道#(5)<#(2),因而问题可以转化求N!中因子5的个数#(5)。这种思路的好处是问题形式统一化了,而不是像我原本思路那样分情况讨论。

求#(5),
     第一种思路就很直接,求1到N各个数中含有因子5个数求和。
     第二种思路书中直接给了个式子,不直观。我的理解就跟上面最开始思路挺像的。从1到N,能被5整除的数的个数为N/5;能被25的数的个数为N/25【被5整除的情况已经被计算,此处只算一次】;...,因此,因子5的总数为(N/5+N/25+N/125+...)。

第二个问题,问二进制形式末尾“0”的个数。
还是问题转化,N!右移一位就减少一个“0”,也相当于除以2。因此,末尾“0”的个数等于N!中因子2的个数。解决方法与题1类似,N/2+N/4+N/8+...。但是书中给了一个更巧妙的捷径,N!中含有质因子2的个数等于N减去N的二进制表示中“1”的个数。书中只给了例子,没有证明。

下面尝试证明,思路是证明 N/2+N/4+N/8+...+二进制中“1”的个数 = N成立:
先给个例子,N =  10 10
则 N/2 = 101, N/4 = N/2 /2 = 10(余数 1), N/8 = N/4 /2 = 1,N/16 = N/8 /2 = 0(余数 1
直观的知道余数1对应着N的二进制表示中的“1”,
因此,做加法的时候从N/16开始: 
N/16+N/16+余数1 = N/8
N/8+N/8 = N/4
N/4+N/4+余数1 = N/2
N/2+N/2 = N
因此,N/2+N/4+N/8+...+二进制中“1”的个数 = N 得证。对于不同的N同样成立。

相关题目那里问的"方幂",原来就是整数幂的意思。
也就是说是100000之类,只有一个“1”,给的提示也是之前《求二进制数中“1”的个数》第三种方法,n>0 && n&(n-1) == 0



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值