【学习现场】20181124的阶乘末尾有多少个0?

640?wx_fmt=png

小史是一个应届生,虽然学的是电子专业,但是自己业余时间每天都会坚持学习编程、计算机、互联网等相关方面的知识,特别是算法的训练。

今天小史又在研究一道算法题了。

【学习现场】

640?wx_fmt=jpeg

小史今天学习了阶乘。

一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。

亦即n!=1×2×3×...×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。

同时,小史也碰到一个问题,要编程求出20181124的阶乘末尾有多少个0。

题目:如何求取20181124的阶乘末尾有多少个0?

题目要求:请编程计算出结果,如果数字过大,给出它对100007取模之后的结果。

小史拿到题目后略微思考,很快有了思路,开始写代码了。读者们,你能比小史更快吗?


学习现场的玩法:

1)计算机编程解决题目,答案在公众号后台进行回复,回复格式为解答+答案,如答案为2,则回复解答2

2)回答正确后,会出现提示,同时有一个交流群的二维码,可进入“场粉交流群”,群内都是算法爱好者和互联网从业人士

3)注意,每道题都有有效期,有效期过后题目作废,只能等待下一道题了

4)学习现场是小史平时练习的题目,下一道题公布的时候,同时会公布上一道题小史的解法供大家参考,也欢迎大家将自己的解法进行留言

5)希望大家玩得开心,这也是最重要的一点


上期回顾:

小史解答:

本题可用动态规划,不了解什么是动态规划的同学可看

1)由于n确定之后,n拆分之后的最大乘积也就确定,所以可以把n拆分之后的最大乘积定义为状态。

2)状态转移:n拆分后的最大乘积 = max ( n-1拆分之后的最大乘积 x 1 , n-2拆分之后的最大乘积 x 2 , n-3拆分之后的最大乘积 x 3 , …… , 1拆分之后的最大乘积 x (n-1))

3)用循环就能计算出100拆分之后的最大乘积,注意,乘积有点大,要用long存储

想清楚了算法细节之后,小史的代码写起来也是非常快,不一会儿就写好了:

MaxProduct.java

/**
 * @author xiaoshi on 2018/11/12.
 */
public class MaxProduct {

    // 中间状态
    private long[] dp = null;

    // 计算中间状态
    private void calcStatus(int n) {
        // 从前往后
        for(int i = 1; i <= n; i++) {
            // 记录最大乘积
            long max = 1L;
            // 拆解
            for(int j = 1; j < i; j++) {
                // 拆出一个j,剩下的要么是(i-j),要么是之前算好的dp[i-j]
                long product = Math.max(dp[i - j] * j, (i - j) * j);
                // 更新最大值
                if(product > max) {
                    max = product;
                }
            }
            // 最大值保存
            dp[i] = max;
        }
    }

    // 入口方法
    public long getMaxProduct(int n) {
        // 初始化dp数组
        dp = new long[n + 1];
        dp[0] = dp[1] = 1L;
        // 计算中间状态
        calcStatus(n);
        // 返回结果
        return dp[n];
    }

}

(友情提示:可左右滑动)

Main.java

/**
 * @author xiaoshi on 2018/11/12.
 */
public class Main {

    public static void main(String[] args) {
        MaxProduct maxProduct = new MaxProduct();
        long result = maxProduct.getMaxProduct(100);
        System.out.println(result);
        System.out.println(result % 100007);
    }

}

(友情提示:可左右滑动)

运行结果

7412080755407364
71144

结束啦?==

如果数字再大一点,long也不够了,数据要溢出。

而且小史很好奇,100到底是怎么被拆分才得到了最大值?

小史断点运行程序,并且打印出一些必要的中间状态,发现100被拆分成了2个2和32个3。

数学方法:

小史用数学的方法仔细分析了一下这个问题,先从简单的入手

1,不用说,最大乘积为1

2,只能拆为1+1,不拆还更好,最大乘积为2

3,只能拆为1+2 或者 1+1+1,不拆还更好,最大乘积为3

4,可以拆为2+2,最大乘积为4

5,可以拆为2+3,最大乘积为6

6,可以拆为2+2+2,也可以3+3,最大乘积为9,这里可知2个3比3个2更好

7,可以拆为3+2+2,最大乘积为12

8,可以拆为2+2+2+2,但是由6知,2个3比3个2更好,所以3个2换成2个3,拆为2+3+3,最大乘积为18

以此类推。

由以上过程可以得到几个结论。

一、4之后,数字拆分得到的最大乘积已经比数字本身要大,所以4之后的数字肯定要拆分。

二、由于2个3比3个2更好,所以尽量拆分出3。

三、一定不要拆分出1,因为白白浪费了一个数。

再进一步,根据尽量拆分出3和不要拆分出1的原则,可以得到以下推论(这里讨论n>4的情况):

如果 n % 3 == 0,最大乘积就是3^(n/3)

如果 n % 3 == 1,最大乘积就是3^((n-4)/3) x 4

如果 n % 3 == 2,最大乘积就是3^((n-2)/3) x 2

有了这个通项公式,再结合快速幂算法和取模特性,可以再log(n)时间内计算出结果,也不用担心数据溢出了。


学习现场是互联网侦察继面试现场后推出的一个姊妹现场,旨在帮助读者进行算法题的训练,同时提供学习交流群,希望对大家的学习和算法提高有所帮助。

640?wx_fmt=jpeg

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值