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