计算n阶乘中尾部零的个数

论坛 期权论坛 脚本     
匿名网站用户   2020-12-20 00:04   29   0

计算n阶乘中尾部零的个数

题目描述:

设计一个算法,计算出n阶乘中尾部零的个数

您在真实的面试中是否遇到过这个题?Yes

样例

11! = 39916800,因此应该返回 2

写在前面

之前在工作中遇到的问题,一般使用一些逻辑,外加一些"野路子"就可以解决.随着遇到的问题的难度的增加,发现自己需要系统学习和实践一些算法了.于是先找到一个题开始进行刷题.以下是我分析和解决的过程,中间不乏一些野路子,但是过程值得进行参考.

常规想法1:

可以写一个方法,先计算出阶乘的结果,然后再对其取余,直到取余结果不为0,就可以统计出结果.代码很快就写出来,但是当输入参数稍大一些,,结果就出错了.原因是阶乘出的结果比较大,超出了long类型的数据范围.

升级想法一:既然在计算阶乘得到的结果比较大,能不能在做阶乘乘法的时候,边取余(同时除以10)计算结果呢?

结果:计算性能有一点提升.但是只能够通过部分数据测试.经过分析发现阶乘计算结果后,除以10,剩下的数据依旧很大,毕竟阶乘中有那么多质数,质数乘以质数一定不能被10整除哈.

升级想法二:如果多次整除10计算出依旧很大,而且是质数乘以质数的结果,那么对要求的结果没有什么意义,我们以把它们清空变成1,继续做乘法.

等等,我如何才能计算出它们是质数和质数的结果呢?反过来一想,什么样的数能够计算出10?是不是只有质数2*5才能计算出来呢?那我只需要统计质因数25就可以喽.

于是书写代码,将每个进行乘法的数据中的25的次数都计算出来.那么我返回那个次数呢?那个小就返回哪个呗.于是加了一个判断.然后自己心里运行了一下,发现好像5的次数一定会小于2,于是直接返回5的次数就OK.

结果如下,到目前为止,算法应该是没有问题了,但是在提交测试的时候,发现计算超时了.

public class Solution {
  
    public long trailingZeros(long input) {
        long result = Method(input);
        return result;
    }
    // 计算阶乘计算中每个数据包含质因数 5的次数
 public static long divideFiveTimes = 0;
    public static long Method(long n) {

  long i = 1;
  for (i = 1; i <= n; i++) {
      //中间计算变量,用于计算除以5后能不能继续被5除掉
   long tempDivideValue = i;
   for (long j = 1; j < tempDivideValue; j++) {
    if (tempDivideValue % 5 == 0) {
     divideFiveTimes++;
     tempDivideValue = tempDivideValue / 5;
    }
   }
  }
  return divideFiveTimes;
 }
}

升级想法三:说实话,到此为止,我有点心急了,因为这个题属于简单的类型,但是自己搞了挺长时间还没有算出来,有点不服,于是决定使用”野路子”找规律来完成这个题目.根据升级想法二:我计算出几个特殊值(5n次幂)时的结果,然后就发现一定的规律了,发现结果和输入条件的关系是result = (n-1)/4;但是还有一个问题,如果阶乘不是不是这几个特殊数据呢?自己观察了一下,直接发现需要可以拆分成其他几个特殊值的和.

输入条件

输出结果

关系

25(5的2次方)

6

*4+1

125(5的3次方)

31

*4+1

625(5的4次方)

156

*4+1

3125(5的5次方)

781

*4+1

15625(5的6次方)

3906

*4+1

15650

3912

15625结果+25的结果

比如我们输入15650,它不是5的整数幂.但是结果可以分解成56次方和52次方结果的和.于是调整了一下就通过了测试.

public class Solution {
  
    public long trailingZeros(long input) {
        long result = newMethod(input);
        return result;
    }
    // 全局变量,统计结果
    public static long methodTotalResult = 0;
 
 public static long newMethod(long n) {
  // 当小于25时,可以直接进行计算
  if (n < 25) {
   methodTotalResult = methodTotalResult + n / 5;
   return methodTotalResult;
  }
  // 和5的n次方进行比较
  long tempNumberCompare = 1;
  for (long i = 1;; i++) {
   tempNumberCompare *= 5;
   if (tempNumberCompare > n) {
    // 输入条件减1,除以4
    methodTotalResult += (tempNumberCompare / 5 - 1) / 4;
    //将剩下的数据进行递归进行运算
    newMethod(n - tempNumberCompare / 5);
    break;
   }
  }
  return methodTotalResult;
 }
}


终于成功了,后来上网搜索了一下,发现一个更好的解决方法,先拷贝下来,以后研究,不过根据测试发现和我上面运行的效率差不多

long count = 0;
        long temp = n/5;
        while (temp!=0) {
            count+=temp;
            temp/=5;
        }
        return count;




分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP