JS实现阶乘

265 阅读2分钟

刚拿到这个题目的时候,觉得没啥难度,刷刷刷写出如下代码

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]