蓝桥杯基础练习 阶乘计算(JAVA)

问题描述

输入一个正整数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

算法思路

    分析题目可知,此题让求n的阶乘,就是求一直从1连乘到n的值。思路很简单,但是考虑到n如果阶乘到1000后,数值肯定会非常大,虽然java中BigInteger类可以解决大数乘法及大数加法,但是这里暂不采用,而是编写一个大数乘法和一个大数加法方法。

程序实现

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int num = input.nextInt();//要求阶乘的数num
        String[] arr = new String[num+5];/用于存储各个num!结果的数组
        for (int i = 1; i <= num; i++) {
            if(i == 1){
                arr[i] = "1";
            }else{
                arr[i] = mutiArr(String.valueOf(i),String.valueOf(arr[i-1]));//调用大数乘法方法
            }
        }
        System.out.println(arr[num]);
    }
    //大整数加法运算方法
    public static String add(String a,String b){
       //当两个数的程度均不超过8位时,直接使用加法运算即可得出结果
       if(a.length() <= 8 && b.length() <= 8){
           return Integer.parseInt(a) + Integer.parseInt(b) + "";
       }
       //设置两个string类型的变量a1、a2,分别用于表示数字a的高位和低八位
       String a1 = "0";
       String a2 = a;
       if(a.length() > 8){//当a的数字长度超过8时对a进行截取
           a1 = a.substring(0,a.length()-8);//数字a的高位
           a2 = a.substring(a.length()-8);//数字a的低八位
       }
        //与a的操作目的一样,这里不再叙述
        String b1 = "0";
        String b2 = b;
        if(b.length() > 8){
            b1 = b.substring(0,b.length()-8);//数字b的高位
            b2 = b.substring(b.length()-8);//数字b的低八位
        }
        String t = add(a2,b2);//变量t用于存储a、b的低八位之和
        while(t.length() < 8) t = "0" + t;//当t的长度不超过8时,需要在t前面补零
        if(t.length() > 8) return add(add(a1,b1),"1") + t.substring(1);//当t的长度超过8时,说明低八位之和向高位有进位,所以高位a1与b1之和应再加1然后,而t应舍弃首位。

        return add(a1,b1) + t;//将高位之和与低位之和拼接得出结果
    }
    //补零,采用递归的方法产生k个零
    public static String zero(int k){
       if(k == 0) return "";
       if(k == 1) return "0";

       int m = k / 2;
       int n = k % 2;

       return zero(m) + zero(m) + zero(n);//利用m + m + n = 来递归的产生指定数目的零
    }
    //大整数加法运算方法
    public static String muti(String s1,String s2){
        //当输入的s1、s2的长度均小于等于4时则采用普通乘法即可
        if(s1.length() <= 4 && s2.length() <= 4){
            return Integer.parseInt(s1) * Integer.parseInt(s2) + "";
        }
        //当s1的长度超过4
        if(s1.length() > 4){
            int k = s1.length() / 2;//将s1以k为分界线拆分
            String a1 = s1.substring(0,k);//s1的高位
            String a2 = s1.substring(k);//s1的低位
            return add(muti(a1,s2)+zero(a2.length()),muti(a2,s2));//高位与s2相乘然后末尾补上s2.length()个零再与低位与
s2相乘结果相加
        }
        return  muti(s2,s1);//当两个if均未匹配上时,说明s2长度超过4,所以交换一下s1与s2的位置
    }
    
    //大整数乘法运算的备忘录算法
    public static String mutiArr(String s1,String s2){
        String key = s1 + "M" + s2;
        String key1 = s2 + "M" + s1;
        //System.out.println(key);
        Map<String,String> map = new HashMap<>();//设置map用于保存已经计算的结果,当涉及重复计算时,可直接从map中取值以减少不必要的计算
        //出口
        if(map.get(key) != null || map.get(key1) != null){
            //System.out.println(map.get(key));
            return map.get(key);
        }
        if(s1.length() <= 4 && s2.length() <= 4){
            //System.out.println(Integer.parseInt(s1) * Integer.parseInt(s2) + "");
            String temp = Integer.parseInt(s1) * Integer.parseInt(s2) + "";
            map.put(key,temp);
            map.put(key1,temp);
            //System.out.println(map.get(key));
            return temp;
        }
        if(s1.length() > 4){
            int k = s1.length() / 2;
            String a1 = s1.substring(0,k);
            String a2 = s1.substring(k);
            String temp = add(muti(a1,s2)+zero(a2.length()),muti(a2,s2));
            map.put(key,temp);
            map.put(key1,temp);
            //System.out.println(map.get(key));
            return temp;
        }
        return  mutiArr(s2,s1);
    }
}
posted @ 2020-03-06 09:31  Alex-jzw  阅读(900)  评论(0编辑  收藏  举报