PAT 基础题6-10 阶乘计算升级版
原本以为基础题都有点小儿科,结果这道题还是有点费劲的。
本题要求实现一个打印非负整数阶乘的函数。
函数接口定义:
void Print_Factorial ( const int N );
其中N是用户传入的参数,其值不超过1000。如果N是非负整数,则该函数必须在一行中打印出N!的值,否则打印“Invalid input”。
裁判测试程序样例:
#include <stdio.h>
void Print_Factorial ( const int N );
int main()
{
int N;
scanf(“%d”, &N);
Print_Factorial(N);
return 0;
}
/* 你的代码将被嵌在这里 */
输入样例:
15
输出样例:
1307674368000
思路
当阶乘的数字到12之后,通常使用的int sum去表示值的方式就不行了,因为int 的所能保存的最高数位为10位,那么我们可以考虑使用数组的方式,将每一个下标分别表示为数字的个、十、百等等数位。题目其实也特别强调了“该函数必须在一行中打印出N!的值”,暗示了这种输出格式可以是数组的循环输出。
那么如何使用数组的方式进行阶乘呢?其实就是将竖乘的方式通过代码实现,同时使用到进位的思想,比如在计算到4的阶乘时,数组的0下标就需要进行相应的进位了,我们可以将这一过程拆开观察,计算到6*4时,得出结果,将num[0]的值由上一次阶乘的结果6改为24的个位4,同时进位,进位的大小为20,但实际上只是num[1]=2,即十位上的数字变为了2。
这里我们就大概能写出一部分进位的代码了,即考虑到各个位上的值的变化,以及进位的值的大小。
那么我们继续往下算,24 * 5,此时结果变为了三位数,但是基本过程是一样的,4 * 5为20,个位取0,进位为20,十位为2,这是第一步,第二步是在20的基础上,用2*5为10,10+2等于12,进位为12。好像又回顾了一遍小学数学是吧?
我不停强调这个过程的原因是因为,在看代码的时候不能被绕晕,每一步计算出的sum结果并不一定代表最后的结果,只有最后没有进位了,才代表计算结束。
同时,要注意,这个竖乘的过程,是数位在不断左移的过程,在代码中通过right++的方式提现出来。
代码
void Print_Factorial ( const int N ){
int sum1=1;
if(N<0) printf("Invalid input");
if(N>=0&&12>=N){
for(int i=1;i<=N;i++) sum1*=i;
printf("%d",sum1);
}
//核心代码区
else if(N>12&&N<=1000){
int num[10000]={0};
num[0]=1;
int right=0;
int carry=0;
int sum2=0;
for(int i=2;i<=N;i++){
for(int j=0;j<=right;j++){
sum2=num[j]*i+carry;
num[j]=sum2 % 10;
carry=sum2 / 10;
}
while(carry){
right++;
num[right]=carry % 10;
carry /= 10;
}
}
for(int k=right;k>=0;k--){
printf("%d",num[k]);
}
}
}