1~N的最小公倍数

题目

输入整数N,计算1~N这N个数的最小公倍数,N<100

思路

思路其实很清晰,只要求得了前N-1个数的最小公倍数a,那么N个数的最小公倍数就是a和N的最小公倍数。求两个整数\(a,b\) 的最小公倍数就是 \(\frac{a\times b}{gcd(a,b)}\)\(gcd(a,b)\)为a和b的最大公约数。看起来似乎很简单,但是这里有个大坑:值越界。
题目中限制了N<100,但是当 N=23 的时候,计算得到的最小公倍数为5354228880已经远远超过了int型的表示范围。

方法一

通过质因数求解。例如对于4和10,4的质因数为(2,2),10的质因数为(2,5)。由于他们有一个公共质因数2,所以最小公倍数为2*2*5=20。
所以第一步先求所有N个数的质因数,重复的质因数只能算一次,接下来将所有质因数相乘就可以得到最小公倍数。但其实这里还是有大数的问题,所以需要通过大数相乘的方法计算,也就是通过数组保存大数。代码如下:

import java.util.Scanner;
public class Main{
    
    public static void main(String[] arg){
        
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        int[] a = new int[105];      // a[1]~a[N]存储   1~N 的N个数的所有质因数
        int[] nums = new int[100];  // 将结果从低位到高位存在一个数组里
        for(int i = 1; i <= 101; i++){
            a[i] = i;
        }
        
        // 计算质因数存到a中
        // 此时实质上a[1]*a[2]*...*a[N]就是1~N的最小公倍数
        // 但直接相乘会数值溢出,因此用数组来进行大数相乘
        for(int i = 2; i <= 101; i++){
            for(int j = i + 1; j <= 101; j++){   
                if(a[j] % a[i] == 0){
                    a[j] /= a[i];
                }
            }
        }
        
        nums[0] = 1;
        // tag存放进位,count存放有效数组长度
        int tag = 0, count = 0;
        for(int i = 2; i <= n; i++){
            if(a[i] > 1){  // 减少不必要的计算
                for(int j = 0; j <= count || tag > 0; j++){
                    int tmp = nums[j] * a[i] + tag;
                    nums[j] = tmp % 10;
                    tag = tmp / 10;
                    if(j > count){  // 更新有效长度
                        count = j;
                    }
                }
            }
        }
        
        while(count >= 0){   // 最后将nums中的有效数字从高位到低位输出
            System.out.print(nums[count]);
            count--;
        }
        System.out.println();
    }
}

方法二

java.math包中提供了BigInteger类用来处理大整数的问题。这里用另一种思路:小于N的质数最大幂乘积的方式。
例如N=10,小于10的质数有:2,3,5,7
对应的最大幂分别为:3,2,1,1(即质数的最大幂次方小于N)
因此前1~10的最小公倍数为2^3 * 3^2 * 5 * 7 = 2520
代码如下:

import java.math.BigInteger;
import java.util.Scanner;
public class Main{
    
    public static void main(String[] arg){
        
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        BigInteger ans = BigInteger.ONE;
        for(int i = 2; i <= n; i++){
            int tmp = 1;
            if(isPrime(i)){
                while(tmp * i <= n){
                    tmp *= i;
                }
            }
            ans = ans.multiply(BigInteger.valueOf(tmp));
        }
        System.out.println(ans);
    }
    
    private static boolean isPrime(int a){
        for(int i = 2; i <= Math.sqrt(a); i++){
            if(a % i == 0){
                return false;
            }
        }
        return true;
    }
}

参考来源

https://blog.csdn.net/sharing_li/article/details/8737855?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-1
https://www.xuebuyuan.com/2857576.html

猜你喜欢

转载自www.cnblogs.com/rezero/p/13179237.html