第一种:分解质因数法
import java.util.HashSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.Scanner;
/*
* @topic:多个正整数的最大公约数和最小公倍数——分解质因数法
*/
/*
* 756 = 2*2*3*3*3*7
* 504 = 2*2*2*3*3*7
* 630 = 2*3*3*5*7
* 2226 = 2*3*7*53
* 最大公约数为4个数的公因子相乘:2*3*7 = 42
* 最小公倍数为4个数不重复因子相乘:2*2*2*3*3*3*5*7*53 = 400680
*/
public class GcdLcm {
static int[] a;//存放正整数
static int n;//正整数个数
static int[] prime = new int[1000];//素数表
static HashSet<Integer> qf = new HashSet<Integer>();//存放所有因子
static HashMap<Integer, Integer> df = new HashMap<Integer, Integer>();//存放重复因子及其个数
public static void main(String[] args) {
// System.out.println("Hello Landor!");
for (int i = 1, j = 0; j < 1000; i++) {
if (isPrime(i))
prime[j++] = i;
}// 建立素数表
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
a = new int[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextInt();
calculate();
System.out.println("最大公约数为:" + getGcd());
System.out.println("最小公倍数为:" + getLcm());
}
public static void calculate() {//依次将每个正整数进行因数分解:756 = 2*2*3*3*3*7
int i, j, count = 0;
for (i = 0; i < n; i++) {
int m = a[i];
for (j = 0; j < 1000 && m > 1; j++) {
Integer key = new Integer(prime[i]);
while (m % prime[j] == 0) {
m /= prime[j];
qf.add(key);//将此因数放进HashSet中(会自动去重)
count++;
}
if (count > 0) {
if (df.get(key) == null) {//如果此因数没有出现过,则直接将因数及其个数放入HashMap中
df.put(key, new Integer(count));
} else if (df.get(key).intValue() < count) {
df.remove(key);//如果出现此因数的个数比hashmap中的个数大,则删除后将新的个数添加
df.put(key, new Integer(count));
}
}
count = 0;
}
}
}
public static int getGcd() {
int gcd = 1, i, j;
Iterator<Integer> it = qf.iterator();
while (it.hasNext()) {//遍历每个qf中的因数,若为公因数则与gcd相乘
i = it.next().intValue();
for (j = 0; j < n; j++) {
if (a[j] % i != 0)//不是公因数
break;
}
if (j == n)
gcd *= i;
}
return gcd;
}
public static int getLcm() {
int lcm = 1;
//System.out.println(df);
for (Map.Entry<Integer, Integer> e : df.entrySet())
lcm *= (int) Math.pow((double) e.getKey().intValue(), (double) e
.getValue().intValue());//遍历HashMap中的Key和Value,将Key的Value次方与lcm相乘
return lcm;
}
public static boolean isPrime(int n) {// 判断素数
int i, step = 4, s = (int) Math.sqrt((double) n + 0.01);
if (n < 1)
System.exit(1);
if (n == 2 || n == 3)
return true;
if (n == 1 || n % 2 == 0 || n % 3 == 0)
return false;
for (i = 5; i <= s; i += step) {
if (n % i == 0)
break;
step ^= 6;
}
return i > s;
}
}
/* 测试实例:
4
756
504
630
2226
最大公约数为:42
最小公倍数为:400680
*/
第二种:辗转相除递推法
import java.util.Scanner;
/*
* @topic:多个正整数的最大公约数和最小公倍数——辗转相除递推法
*/
/*
* 先求gcd:
* (756,504):756%504 = 252 ,504%252 = 0 ,所以(756,504)=252
* (630,252):630%252 = 126 ,252%126 = 0, 所以(630,252)=126
* (2226,126):2226%126 = 84,126%84 = 42,84%42=0,所以(2226,126)=42
* 所以4个数的最大公约数为:(756,504,630,2226)=42
* 再求lcm:
* [756,504]=756*504/252=1512
* [1512,630]=1512*630/126=7560 注意,此处的126和上面所求126没有关系,这里的126是需要求gcd(1512,630)得到的
* [7560,2226]=7560*2226/42=400680
* 所以4个数的最小公倍数为:[756,504,630,2226]=400680
*/
public class GcdLcm1 {
static int[] a;// 存放正整数
static int n;// 正整数个数
public static void main(String[] args) {
// System.out.println("Hello Landor!");
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
a = new int[n];
for (int i = 0; i < n; i++)
a[i] = sc.nextInt();
System.out.println("最大公约数为:" + getGcd());
System.out.println("最小公倍数为:" + getLcm());
}
public static int getGcd() {
int p = a[0];
for (int i = 1; i < n; i++)
p = gcd(Math.max(p, a[i]), Math.min(p, a[i]));
return p;
}
public static int getLcm() {
int lcm = a[0];
for (int i = 1; i < n; i++)
lcm *= (a[i] / gcd(Math.max(lcm, a[i]), Math.min(lcm, a[i])));
return lcm;
}
public static int gcd(int x, int y) {
return (y == 0) ? x : gcd(y, x % y);
}
}
第三种:逐次想减、相除法
逐次相减是用来求最大公约数的,是辗转相除的一种推广
算法描述:
先将m个数由大到小排序,再逐次相减修改各元素的值。设排序后相邻的两个数为A、B(A≥B)。再设n=1、2、3.....,各个A同时按下述方法重新赋值:
如A>n*B ,则A=A-n*B>0,n是满足条件的最大整数,相当于A=A%B;
如A=B,A不变;
如A=n*B,n≠1,则A=A-(n-1)*B,即取A=B,A不能小于1;
例如:求最大公约数(756,504,630,2226)
①4个数排序,再从左到右逐次相减:
(756,504,630,2226)=(2226,756,630,504)=(2226-2*756,756-630,630-504,504)=(714,126,126,504)
②再排序,逐次相减:
(714,126,126,504)=(714,504,126,126)=(210,504-3*126,126,126)=(210,126,126,126)
③再排序,逐次相减:
(210,126,126,126)=(84,126,126,126)=(126,126,126,84)=(126,126,42,84)=(126,126,84,42)=(126,42,42,42)
=(126-2*42,42,42,42)=(42,42,42,42)
此时,四个数相同,完毕,最大公约数为42
main()
{
long a[4]={756,504,630,2226},i,j,t;
printf("最大公约数:(%ld,%ld,%ld,%ld)\n",a[0],a[1],a[2],a[3]);
h:for(i=0;i<3;i++) {
for(j=i+1;j<=3;j++)
if(a[i]<a[j]){
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
printf("=(%ld,%ld,%ld,%ld)\n",a[0],a[1],a[2],a[3]);
if(a[0]==a[3]){
printf("=%ld\n\n",a[0]);
exit(0);
}else{
for(i=0;i<3;i++){
if(a[i]%a[i+1]!=0)
a[i]=a[i]%a[i+1];
else
a[i]=a[i+1];
}
printf("=(%ld,%ld,%ld,%ld)\n",a[0],a[1],a[2],a[3]);
goto h;
}
}
逐次相除:用来求最小公倍数
设有若干数,其中最大的为a,用a的1倍、2倍、3倍、…,除以其余的各数,若第n次恰好都除尽,则此时的n*a即为它们的最小公倍数
这个算法比较SB,就不贴代码了,有兴趣自己写一下。