对于如何算 n 的阶乘,只要你知道阶乘的定义,我想你都知道怎么算,但如果在面试中,面试官抛给你一道与阶乘相关,看似简单的算法题,你还真不一定能够给出优雅的答案!本文将分享几道与阶乘相关的案例,且难度递增。

案例一

给定一个整数 N,那么 N 的阶乘 N! 末尾有多少个 0?例如: N = 10,则 N!= 3628800,那么 N! 的末尾有两个0。

有些人心想,这还不简单,直接算出 N!的值,然后用除以 10 来判断多少个 0 就可以了。

有些人则这样想,直接算 N!的值再来除以 10 判断多少个 0 的话肯定会出现溢出问题,于是开始思索:一个数乘以 10 就一定会在末尾产生一个零,于是,我们可以从“哪些数相乘能够得到 10 ”入手。

没错,只有 2 * 5 才会产生 10。

注意,4 * 5 = 20 也能产生 0 啊,不过我们也可以把 20 进行分解啊,20 = 10 * 2。

于是,问题转化为 N! 种能够分解成多少对 2*5,再一步分析会发现,在 N!中能够被 2 整除的数一定比能够被 5 整除的数多,于是问题就转化为求 1…n 这 n 个数中能够被 5 整除的数有多少个,注意,像 25 能够被 5整除两次,所以25是能够产生 2 对 2 * 5滴。有了这个思路,代码如下:

int f(int n){int sum = 0;for(int i = 1; i <= n; i++){int j = i;while(j % 5 == 0){sum++;j = j / 5;}}return sum;
}
复制代码

有些人想出了这个规律,很是得意,然而,这还不是面试官要的答案,大家想一个问题,

当 N = 20 时,1~20 可以产生几个 5 ?答是 4 个,此时有 N / 5 = 4。

当 N = 24 时,1~24 可以产生几个 5 ?答是 4 个,此时有 N / 5 = 4。

当 N = 25 时,1~25 可以产生几个 5?答是 6 个,主要是因为 25 贡献了两个 5,此时有 N / 5 + N / 5^2 = 6。

可以发现 产生 5 的个数为 sum = N/5 + N/5^2 + N/5^3+….

于是,最优雅的写法应该是这样:

int f(int n){int sum = 0;while(n! = 0){sum += n / 5;n = n / 5;}
}
复制代码

这时,你就可以自信这把代码扔给面试官了。

案例2

求 N! 的二进制表示中最低位 1 的位置。例如 3!=6,二进制为 1010,所以 最低位 1 的位置在第二位。

没有思路?请仔细想一下这道题与上道题的关系!

仔细想一下,这道题不也是求末尾有多少个 0 吗?你求出了末尾有多少个0自然知道 1 的位置(0的个数加1就是1的位置了),只不过,这道题是求二进制末尾有多少个 0。

由于是二进制,所以每次乘以 2 末尾就会产生一个 0 。

于是,模仿上面一道题,求 N!含有多少个 2 的个数。心想,幸好我做个类似了,于是一波操作猛如虎,一分钟就写出了代码:

int f(int n){int sum = 0;while(n! = 0){sum += n / 2;n = n / 2;}
}
复制代码

面试官:还能在优化吗?

什么鬼?还要在优化?我都 O(logn) 时间复杂度了。

还记得我之前讲解了几道有关位运算的吗?这道题确实可以用位运算来优化,除以 n / 2 == n >> 1。不过位运算的速度快多了,于是,优化后的代码如下:

int f(int n){int sum = 0;while(n! = 0){n >>= 1;sum += n;}
}
复制代码

还能在优化吗?

可以,不过我先不讲,因为我觉得,这已经够快了。后面讲其他题可能会把这道题再拿出来讲。

如果你能写出这样的代码,已经算很牛逼了。

案例三

给你一个数 N,输出 N! 的值。

没错,就是这么简单,直接让你求阶乘的值。

这个时候,你就要小心了,千万别一波操作

long long sum = 1;
for(int i = 1; i <= n; i++){sum *= i;}
复制代码

一个 for 循环,马上搞定。

因为你不知道 n 的范围,有可能你用 long long 也是会溢出的,所以这个时候应该要问一下面试官有没有限定 n 的范围。

面试官:没有限定!

这下好了,这道阶乘的题,难度顿时上升了,说实话,我敢保证大部分人还真没去实现过。所以,今天我就带大家来实现一下,以防以后真的被问到。结果最熟悉的题顿时不知道怎么下手好。

这个时候,我们就必须用字符串来存放所求的值的,在相乘的时候也是用字符串来相乘,说白了,就是要会求两个大整数相乘

下面我们先来实现一个求两个大整数相乘的函数。一种比较简单的方法就是,像我们小学那会一样,让个位数与另一个数的其他数相乘,然后让十位数与另一个的其他数相乘,最后在把他们进行相加。

实现代码如下:

    public static String mul(String s1, String s2) {// 先把字符串转化为 字符数组。char[] c1 = s1.toCharArray();char[] c2 = s2.toCharArray();int len = c1.length + c2.length;// 用来存放两个数的积,字符的初始值为 '\u0000',也就是 0char[] c = new char[len];// 由于大整数的低位是在字符串的末尾,所以我们从末尾遍历来计算for (int i = c1.length - 1; i >= 0; i--) {int index = len - 1;int res = 0;//用来存放进位for (int j = c2.length - 1; j >= 0; j--) {int temp = (c1[i]-'0') * (c2[j]-'0') + c[index] + res;res = temp / 10;c[index--] = (char)(temp % 10);}// 每趟乘下来的进位要进行保存。c[index] = (char)res;len--;}// 最后把c中的字符加上 '0'for (int i = 0; i < c.length; i++) {c[i] += '0';}String s = new String(c);// n位数乘以m位数得到积位 (m+n)位数或者(n+m-1)位数// 我们只需要判断c[0]是否为0,为0则把它舍弃。if(c[0] == '0')return s.substring(1);elsereturn s;}
复制代码

注意,一定要自己实现一遍,一定要自己实现一遍,因为原理简单,但手动实现就不一定那么简单了,容易出现bug。

采用这种方法的话,两个大整数相乘的时间复杂度为 O(n),其实还有更快的方法,大概时间复杂度是 O(n^1.6),不过代码有点小复杂。

知道了两个大整数相乘之后,我们再来算我们的阶乘,就好做了,我们每次相乘的时候,只需要把它当作两个大整数重复乘就可以了。代码如下:

    // N 的阶乘public static String f(int n) {String s = "1";Integer t = null;for (int i = 2; i <= n; i++) {t = i;s = 大整数相乘.mul(s,t.toString());}return s;}// 大整数相乘public static String mul(String s1, String s2) {// 先把字符串转化为 字符数组。char[] c1 = s1.toCharArray();char[] c2 = s2.toCharArray();int len = c1.length + c2.length;// 用来存放两个数的积,字符的初始值为 '\u0000',也就是 0char[] c = new char[len];// 由于大整数的低位是在字符串的末尾,所以我们从末尾遍历来计算for (int i = c1.length - 1; i >= 0; i--) {int index = len - 1;int res = 0;//用来存放进位for (int j = c2.length - 1; j >= 0; j--) {int temp = (c1[i]-'0') * (c2[j]-'0') + c[index] + res;res = temp / 10;c[index--] = (char)(temp % 10);}// 每趟乘下来的进位要进行保存。c[index] = (char)res;len--;}// 最后把c中的字符加上 '0'for (int i = 0; i < c.length; i++) {c[i] += '0';}String s = new String(c);// n位数乘以m位数得到积位 (m+n)位数或者(n+m-1)位数// 我们只需要判断c[0]是否为0,为0则把它舍弃。if(c[0] == '0')return s.substring(1);elsereturn s;}
复制代码

时间复杂度是 O(n^3)。如果要优化的话,主要是在大整数相乘这里进行优化。

总结

是不是觉得,阶乘也没有那么简单了?这三道与阶乘相关的题,应该是比较常见的题吧,今天跟大家分享一波,希望大家有时间的话,自己也用代码实现一下,特别是算 N!。后面会继续跟大家分享一些我觉得不错的算法题以及一些算法技巧,敬请关注。

转载于:https://juejin.im/post/5c909c25f265da611d742410

阶乘很简单?恕我直言,阶乘相关的面试题你还真不一定懂!相关推荐

  1. linux写一个10的阶乘,C语言练习题:求1到10的阶乘之和简单实例

    C语言练习题:求1到10的阶乘之和简单实例 C语言练习题:求1到10的阶乘之和简单实例 #include int factorial(int n) { if(0==n) return 1; if(1= ...

  2. 7-100 简单求阶乘问题 (10 分)本题要求编写程序,计算N的阶乘。输入格式:输入在一行中给出一个不超过12的正整数N。输出格式:在一行中输出阶乘的值。输入样例:4结尾无空行

    7-100 简单求阶乘问题 (10 分) 本题要求编写程序,计算N的阶乘. 输入格式: 输入在一行中给出一个不超过12的正整数N. 输出格式: 在一行中输出阶乘的值. 样例">输入样例 ...

  3. 2021.11.18 简单计算阶乘(多种方法)及 求阶乘的和

    运用各种方法计算阶乘及阶乘之和 三种方法计算阶乘 一.利用for循环法 二.利用导入库法计算阶乘 三.利用函数递归法 在原有基础上计算阶乘之和 学习方向: 三种方法计算阶乘 一.利用for循环法 &q ...

  4. java 阶乘尾部的零,阶乘算法全集,阶乘末尾非零位,阶末尾零的个数

    阶乘相关算法及程序 有关阶乘的算法,不外乎两个方面:一是高精度计算:二是与数论相关. 一. 高精度计算阶乘 这实际上是最没有技术含量的问题,但是又会经常用到,所以还是得编写,优化它的计算. 首先看小于 ...

  5. python求阶乘之和_python计算阶乘前n项和

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 知道公式后就很简单了,利用for循环,第几行i+1就等于几,当然python中是 ...

  6. python求50的阶乘_python中求阶乘

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 我如何去计算python中的一个整数的阶乘?... 写一个猜数字的游戏,预先设定 ...

  7. python求50的阶乘_python中的阶乘

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 我如何去计算python中的一个整数的阶乘?... 问题描述 阶乘是我们在很多的 ...

  8. 很多人说单片机很简单,有些本专业学生为什么学起来这么吃力?

    大家好,我是无际单片机编程的徐工. 在网上看到这么一个话题,自己特别有感触,不自觉的想写一下自己的看法. 单片机编程,我们的教材是<单片机原理及应用>. 当时我们的很多同学都觉得单片是最难 ...

  9. foreach判断最后一个_JavaScript很简单?那你理解的forEach真的对吗?

    你理解的Array.prototype.forEach真的对吗? Array.prototype.forEach 我们都知道,forEach() 方法对数组的每个元素执行一次给定的函数.它的语法也很简 ...

  10. 【结果很简单,过程很艰辛】记阿里云Ons消息队列服务.NET接口填坑过程

    Maybe 这个问题很简单,因为解决方法是非常简单,但填坑过程会把人逼疯,在阿里云ONS工作人员.同事和朋友的协助下,经过一天的调试和瞎捣鼓,终于解决了这个坑,把问题记下来,也许更多人在碰到类似问题的 ...

最新文章

  1. 漫画:如何给女朋友解释什么是删库跑路?
  2. JavaMail的体系结构及发送复杂邮件
  3. 《构建之法》需求分析 读书笔记 Week6
  4. CSP认证201803-3 URL映射[C++题解]:字符串处理、模拟
  5. python datetime timedelta函数_Python Pandas DatetimeIndex.to_perioddelta()用法及代码示例
  6. 科大星云诗社动态20210421
  7. 解神者php奥义高阶,《解神者》角色月曦九攻略技能解析和兽主推荐
  8. RTSP协议分析(二)
  9. clob mybatis_spring + mybatis 存取clob
  10. collection集合 地址_有容乃大--Java 集合(List/Set/Map)
  11. ES6新特性_ES6语法糖-class中的getter和setter设置---JavaScript_ECMAScript_ES6-ES11新特性工作笔记038
  12. 9.2.2、Libgdx的输入处理之事件处理
  13. 目标检测——域自适应只对同源的样本有效
  14. 20180513 实参 形参
  15. pxe安装系统 ip获取错误_聊聊PXE的那点东西
  16. vim 操作命令大全
  17. C语言函数大全 chm含示例
  18. short 的算术运算
  19. 嵌入式计算机 硬盘录像机,嵌入式数字硬盘录像机安装步骤 硬盘安装及使用注意事项【详细介绍】...
  20. BC26 OPEN开发之--LWM2M连接分析

热门文章

  1. 2D纸娃娃系统的web演示
  2. 跟着莫烦python 从零开始强化学习之Q-Learning 一维探索者 代码完整注释版
  3. 人人开源项目搭建到服务器,人人开源系列项目介绍以及环境搭建
  4. 用外挂只为“吃鸡”成功?为什么不试试正当手段!
  5. 关于中标麒麟系统出现“网络管理器未响应”这件事的解决办法
  6. 数据库可疑修复的方法
  7. 如何将计算机网络作为热点,教你如何三步让笔记本电脑做wifi热点??
  8. 时间序列预测算法----Prophet
  9. Siamese Network(孪生网络)
  10. sql连接本地数据库