1 問題描述
Compute the Greatest Common Divisor of Two Integers using Sieve of Eratosthenes.
翻譯:使用埃拉托色尼篩選法計算兩個整數的最大公約數。(PS:最大公約數也稱最大公因數,指兩個或多個整數共有約數中最大的一個)
2 解決方案
2.1 埃拉托色尼篩選法原理簡介
引用自百度百科:
埃拉托色尼篩選法(the Sieve of Eratosthenes)簡稱埃氏篩法,是古希臘數學家埃拉托色尼(Eratosthenes 274B.C.~194B.C.)提出的一種篩選法。 是針對自然數列中的自然數而實施的,用於求一定范圍內的質數,它的容斥原理之完備性條件是p=H~。
具體求取質數的思想:
(1)先把1刪除(現今數學界1既不是質數也不是合數)
(2)讀取隊列中當前最小的數2,然后把2的倍數刪去
(3)讀取隊列中當前最小的數3,然后把3的倍數刪去
(4)讀取隊列中當前最小的數5,然后把5的倍數刪去
(5)如上所述直到需求的范圍內所有的數均刪除或讀取
下面看一下執行上述步驟求不大於100的所有質數的一個示意圖:
2.2 具體編碼
本文求取兩個數的最大公約數,采用質因數分解法:把每個數分別分解質因數,再把各數中的全部公有質因數提取出來連乘,所得的積就是這幾個數的最大公約數。
例如:求24和60的最大公約數,先分解質因數,得24=2×2×2×3,60=2×2×3×5,24與60的全部公有的質因數是2、2、3,它們的積是2×2×3=12,所以,(24,60)=12。
此處,第一步,先使用埃拉托色尼篩選法求取不大於數A的所有質數,然后從這些質數中選取A的所有質因數;第二步,依照第一步思想求取數B的所有質因數;第三步,求取數A和數B公共質因數;第四步,輸出數A和數B的最大公約數。
具體代碼如下:
package com.liuzhen.ex1; import java.util.Scanner; public class SieveOfEratosthenes { //返回一維數組,數組中的元素為不大於n的所有質數 public static int[] getPrime(int n){ int[] result1 = new int[n]; //定義一個一維數組,並從第2個元素依次初始化為相應的自然數 for(int i = 2;i < n+1;i++){ result1[i-1] = i; } for(int i = 2;i < n;i++){ for(int j = i+1;j < n+1;j++){ if(j % i == 0) //如果j能夠整除i,使result[j-1]等於0 result1[j-1] = 0; } } int[] result2 = getNoneZero(result1); //除去result數組中所有0元素 return result2; //數組中非零元素即為不大於n的所有質數 } //返回一維數組,該數組的元素為參數數組中所有不為0的元素值 public static int[] getNoneZero(int[] A){ int len = 0; for(int i = 0;i < A.length;i++){ if(A[i] != 0) len = len+1; } int[] result = new int[len]; int k = 0; for(int i = 0;i < A.length;i++){ if(A[i] != 0){ result[k] = A[i]; k++; } } return result; } //求取一個數n的所有質因數(eg:24=2×2×2×3,則result[] = {2,2,2,3}) public static int[] getNprime(int n){ int[] primes = getPrime(n); int[] result; //最終返回結果集 int len = 0; //返回結果集數組長度,初始化為0 for(int i = 0;i < primes.length;i++){ int temp = n; while(temp % primes[i] == 0){ temp = temp/primes[i]; len++; } } result = new int[len]; int k = 0; for(int i = 0;i < primes.length;i++){ int temp = n; while(temp % primes[i] == 0){ temp = temp/primes[i]; result[k] = primes[i]; k++; } } return result; } //返回兩個一維數組中所有共同元素 public static int[] getCommonPrime(int[] A , int[] B){ int[] result; int lenA = A.length; int lenB = B.length; if(lenA < lenB){ result = new int[lenA]; for(int i = 0;i < lenA;i++){ int temp = A[i]; for(int j = 0;j < lenB;j++){ if(temp == B[j]){ result[i] = A[i]; B[j] = 0; break; } } } } else{ result = new int[lenB]; for(int i = 0;i < lenB;i++){ int temp = B[i]; for(int j = 0;j < lenA;j++){ if(temp == A[j]){ result[i] = B[i]; A[j] = 0; break; } } } } int[] result1 = getNoneZero(result); return result1; } //求取數A和B的最大公約數 public static void getMaxCommonDivisor(int A,int B){ int[] primesA = getNprime(A); //數A所有質因子 int[] primesB = getNprime(B); //數B所有質因子 int[] resultPrime = getCommonPrime(primesA,primesB); //數A和數B的公共質因數 int maxCommonDivisor = 1; System.out.println(A+"和"+B+"的公共質因數為:"); for(int i = 0;i < resultPrime.length;i++){ maxCommonDivisor *= resultPrime[i]; System.out.print(resultPrime[i]+"\t"); } System.out.println(); System.out.print(A+"和"+B+"的最大公約數為:"+maxCommonDivisor); } public static void main(String[] args){ System.out.println("請輸入數字A和數字B的值:"); Scanner in = new Scanner(System.in); int a = in.nextInt(); int b = in.nextInt(); getMaxCommonDivisor(a,b); } }
運行結果:
請輸入數字A和數字B的值: 100 60 100和60的公共質因數為: 2 2 5 100和60的最大公約數為:20 請輸入數字A和數字B的值: 60 48 60和48的公共質因數為: 2 2 3 60和48的最大公約數為:12 請輸入數字A和數字B的值: 120 54 120和54的公共質因數為: 2 3 120和54的最大公約數為:6