大数阶乘

本文探讨了如何处理大数阶乘的计算问题,包括使用高精度算法避免溢出,以及通过动态规划和 memoization 技术提高计算效率。同时,文章还介绍了常见的数学优化技巧,如斯特林公式,来估算大数阶乘,以降低实际计算需求。
摘要由CSDN通过智能技术生成
import java.util.ArrayList;
import java.util.List;

/**
 * 实现思路:
 *  Step 1:int转int[]
 *  Step 2:int[] 相乘
 *  Step 3: 将数组乘积求和
 *  Step 4: 遍历1到n,反复上述 Step 1 - 3即可
 *
 * 注意:1,处于后续的计算方便,在整数转成int数组时,需要进行翻转处理;Eg:123转化成数组为:[3,2,1],即整数的个位在数组的0位置
 *
 * @author yhyr
 * @since 2019/09/11 0:27
 */
public class Factorial {
    public static void main(String[] args) {
        Factorial factorial = new Factorial();
        System.out.println(factorial.factorial(20));
    }

    private String factorial(int num) {
        String result = "1";
        if (num == 0) {
            return result;
        }
        for (int i = 2; i <= num; i++) {
            int[] resultArray = str2IntArray(result);
            int[] tmpArray = str2IntArray(String.valueOf(i));
            List<String> mutList = arrayMultiplication(resultArray, tmpArray);
            result = sumStrList(mutList);
        }
        return result;
    }

    private String sumStrList(List<String> strList) {
        int[] resultArray = str2IntArray(strList.get(0));
        for (int i = 1; i < strList.size(); i++) {
            int[] strArray = str2IntArray(strList.get(i));
            resultArray = addIntegerArray(resultArray, strArray);
        }
        StringBuilder sb = new StringBuilder();
        for (int i = resultArray.length - 1; i >= 0; i--) {
            sb.append(resultArray[i]);
        }
        return sb.toString();
    }

    private int[] addIntegerArray(int[] array1, int[] array2) {
        int index = 0;
        boolean bitFlag = false; // 进位标识符
        if (array1.length < array2.length) {
            // 规定长度上的为array1,短的为array2
            int[] tmp = array2;
            array2 = array1;
            array1 = tmp;
        }

        while (index < array2.length) {
            int tmp = array1[index] + array2[index];
            if (bitFlag) {
                tmp += 1;
                bitFlag = false;
            }
            if (tmp < 10) {
                array1[index] = tmp;
            } else {
                array1[index] = tmp - 10;
                bitFlag = true;
            }
            index++;
        }
        if (bitFlag) {
            if (index == array1.length) {
                // 扩容处理
                int[] tmp = new int[array1.length + 1];
                for (int i = 0; i < array1.length; i++) {
                    tmp[i] = array1[i];
                }
                tmp[index] = 1;
                return tmp;
            }
            array1[index] += 1;
        }
        return array1;
    }

    /**
     * 数组乘法
     *
     * 实现思路:分别计算每一位的乘积,并用0对结果进行补位。
     *
     * Eg:24 * 25 计算思路:
     *   4 * 5 = 20 不补0
     *   2 * 5 = 10 补一个0 => 100
     *   4 * 2 = 8 补一个0 => 80
     *   2 * 2 = 4 补两个0 => 400
     * 故最终结果为:[20,100,80,400],对结果集求和即就是最终结果:600
     *
     * 补0判断依据:根据两个数在数组的下标进行判断:
     *	 下标均为0,则不补零
     *	 一个下标为0另一个为1,则补1一个零
     *	 下标均为1,则补两个零
     *
     * @param array1
     * @param array2
     * @return
     */
    private List<String> arrayMultiplication(int[] array1, int[] array2) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array2.length; j++) {
                int tmp = array1[i] * array2[j];
                StringBuilder tmpStr = new StringBuilder(String.valueOf(tmp));
                for (int k = 0; k < i + j; k++) {
                    tmpStr.append("0");
                }
                result.add(tmpStr.toString());
            }
        }
        return result;
    }

    private int[] str2IntArray(String str) {
        char[] chars = str.toCharArray();
        int[] result = new int[chars.length];
        int index = 0;
        for (int i = chars.length - 1; i >= 0; i--) {
            result[index++] = Integer.valueOf(String.valueOf(chars[i]));
        }
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值