刚拿到这个题目的时候,觉得没啥难度,刷刷刷写出如下代码
let factorial = (n) =>{ let num = 1
for(let i = 0;i<=n;i++){
num *= i
}
return num
}然后面试官说,可以用递归实现吗,我想了一下,写出了这玩意(完蛋)
let factorial = (n) =>{ if(n == 1) return 1
return n * func(n-1)
}面试官:你这如果传入的n过大,就会导致栈溢出啊,有什么优化方案吗?
(这个栈溢出直接把我问懵了,现在回顾发现原来就是递归没有结束,持续压栈导致了栈溢出,但是当时我没反应过来!!!裂开)
栈溢出优化方案如下:
let factorial = (n) =>{
calculate(n, 1);
}
let calculate = (n, num){
if(n == 1) return num
return calculate(n-1, num * n)
}通过尾递归防止栈溢出,但是仍有个问题,无法解决大数的阶乘出现Infinity)
于是继续优化,解决大数精确阶乘方案如下:
let factorial = (n) => {
let res = [1]
for(let i = 2;i <= n;i++){
let c = 0
for(let j = 0; j < res.length || c!== 0;j++){
c += (res[j] || 0) * i
res[j] = c % 10
c = Math.floor(c / 10)
}
}
return res.reverse().join('')
}最终代码的大概思路是:从1乘到n,然后把结果的每一位数都去乘当前的乘数,通过数组去存储结果的每一位数
拿计算 5!来过一遍流程吧(存放结果的数组中着重标记的代表此时更新的值)
第一遍遍历 n = 1
res = [1]
第二遍遍历 n = 2
c = 1 * 2
res = [2]
第三遍遍历 n = 3
c = 2 * 3 = 6
res = [6]
第四遍遍历 n = 4
c = 6 * 4 = 24
res = [4]
c = 24 / 10 + 0 * 4 = 2
res = [4, 2]
第五遍遍历 n = 5
c = 4 * 5 = 20
res = [0, 2]
c = 20 % 10 + 2 * 5 = 12
res = [0, 2]
c = 12 / 10 + 0 * 5 = 1
res = [0,2,1]