基础练习 阶乘计算
时间限制:1.0s 内存限制:512.0MB
问题描述
输入一个正整数n,输出n!的值。
其中n!=1*2*3*…*n。
算法描述
n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法。使用一个数组A来表示一个大整数a,A[0]表示a的个位,A[1]表示a的十位,依次类推。
将a乘以一个整数k变为将数组A的每一个元素都乘以k,请注意处理相应的进位。
首先将a设为1,然后乘2,乘3,当乘到n时,即得到了n!的值。
输入格式
输入包含一个正整数n,n<=1000。
输出格式
输出n!的准确值。
样例输入
10
样例输出
3628800
代码实现
import java.util.Scanner;
public class Main {
static Scanner s = new Scanner(System.in);
static final int MAX = 3000;
public static void main(String[] args) {
int n = s.nextInt();
//long ct1 = System.currentTimeMillis();
if (n < 0 || n > 1000) {
return;
}
if (n == 0) { // 注意0!=1
System.out.println(1);
return;
}
if (n == 1) {
System.out.println(1);
return;
}
int[] A = new int[MAX];
int[] mark = new int[MAX]; //用来标记A数组中被处理过的数据,处理过标记为1,否则为0
A[0] = 1; // 初始化
// k是乘数,从1-n。
int index = 0;
// index表示已经被用的数组下标
for (int k = 1; k <= n; k++) {
for (int j = 0; j <= index; j++) { // 这层循环是保证每一个数字都被c乘
A[j] *= k;
}
for (int i = 0; i <= index; i++) { // 这层循环用来进行进位的处理
if (A[i] > 9) {
A[i + 1] += A[i] / 10;
A[i] %= 10;
if(mark[i]==0){
index++; //这里有问题,导致运算时间增加了很多
mark[i]=1; //添加mark来解决index的问题
}
}
}
}
for (int j = index; j >= 0; j--) {
System.out.print(A[j]);
}
//long ct2 = System.currentTimeMillis();
//System.out.println("\n算法总耗时:" + (ct2 - ct1) + " ms");
//System.out.println("\n结果有:"+index+"位");
}
}
算法思路
- 这题考的就是大数的阶乘,测试数据到了1000,1000阶乘的结果有2567位,算法总耗时:33 ms
- 这题我花了很长时间才做出来,因为在之前提交的时候,最后有2组数据不能通过,分别是997和1000,显示运算超时。百度其他人的代码,表示看不太懂,主要的问题就在于如何来计算A数组中用了几位。
- 使用index来记录数组A中用了几位,然后再来判断数组中的数据,是否大于9,如果大于,就进行进位处理,同时来用mark数组做标记(如:A[0]进行了进位处理后,if (mark[0] == 0) { mark[0]=1;index++; },当A[0]再次被处理时,index就不会进行自加)。
- 如:5!=120,在数组中存的就是0 2 1,此时index应该为3。在此过程中 n=5
- ①、A[0]=1,k=1;
- ②、A[0]=2,k=2 ③、A[0]=6,k=3
- ④、A[0]=24,k=4,同时进行进位处理,A[0]=4,A[1]=2,index=1(表示A数组被用了2位),mark[0]=1(表示第一位已经被处理过了);
- ⑤、A[0]=20,A[1]=10,k=5,然后A[0]进行进位处理,此时mark[0]=1,所以index不变,再A[1]进行进位处理,此时index++,mark[1]=1;结果是:A[0]=0,A[1]=2,A[2]=1
- ⑥、结果输出,从A中取出A[index] A[index-1] A[index-2]就是结果120
- 此算法肯定不是最好的写法,使用的辅助变量比较多,敬请各位原谅
注:本程序原理不是很难,所以加的注释不算多,本人一向相信一个观念——不加注释的程序,不是一个好的程序。