第一種:分解質因數法
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,就不貼代碼了,有興趣自己寫一下。