數論問題:最大公約數的3種求法

幾個整數中公有的約數,叫做這幾個數的公約數;其中最大的一個,叫做這幾個數的最大公約數

例如:12、16的公約數有1、2、4,其中最大的一個是4,4是12與16的最大公約數,一般記爲(12,16)=4。12、15、18的最大公約數是3,記爲(12,15,18)=3。

最大公約數有以下幾種求法:

第一種:輾轉相除法(歐幾里得算法)

已知 a = ms,b = ns,a = tb + r ,其中 a > b,求a,b的最大公約數s。

r = a - tb = ms - tns = (m - tn) s 即 a 與 b 的最大公約數GCD(a,b)相當於 r 與 b 的最大公約數GCD(b,r)。

如果其中一個數爲0,則另一個數爲最大公約數

例:10和35

過程爲:GCD(10,35) = GCD(35,10) = GCD(10,5) = GCD(5,0) = 5

1、由10除以35,餘數爲10得到(35,10)

2、由35除以10,餘數爲5得到(10,5)

3、由10除以5,餘數爲0得到(5,0)

4、最後得最大公約數5

import java.util.Scanner;

public class Gcd {
    // 計算輸入的兩個整數的最大公約數
    // 用變量 m 和 n 存儲兩個數的值,如果n爲0,程序結束,m的值爲最大公約數
    // 否則計算m除以n的餘數,把n保存到m中,並且把餘數保存到n。
    // 重複這個過程,每次都先判定n是否爲0。
    // 輾轉相除法

    public static int getGcd(int m,int n){
        if(n == 0) {
            System.out.println(String.format("GCD(%d,%d)",m,n));
            return m;
        }
        else {
            int r = m % n;
            int c = m / n;
            System.out.println(String.format("GCD(%d,%d)",m,n));
            System.out.println(String.format("%d / %d = %d …… %d",m,n,c,r));
            m = n;
            n = r;
            return getGcd(m,n);
        }
    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("Please input 2 numbers:");
        int num1 = sc.nextInt();
        int num2 = sc.nextInt();
        int gcd = getGcd(num1,num2);
        System.out.println(String.format("%d 和 %d的最大公約數爲 %d",num1,num2,gcd));

    }

}

運行結果如下: 

Please input 2 numbers:
98 63
GCD(98,63)
98 / 63 = 1 …… 35
GCD(63,35)
63 / 35 = 1 …… 28
GCD(35,28)
35 / 28 = 1 …… 7
GCD(28,7)
28 / 7 = 4 …… 0
GCD(7,0)
98 和 63的最大公約數爲 7

 

第二種:更相減損法

已知 a = ms,b = ns,其中 a > b,求a,b的最大公約數s。

r = a - b = ms - ns = (m - n)s 即 a 與 b 的最大公約數GCD(a,b)相當於 r 與 b 的最大公約數GCD(b,r)。

如果其中一個數爲0,則另一個數爲最大公約數

例:10和35

過程爲:GCD(10,35) = GCD(35,10) = GCD(25,10) = GCD(15,10) = GCD(10,5) = GCD(5,5) = 5

1、由35減10,差爲25得到(25,10)

2、由25減10,差爲15得到(15,10)

3、由15減10,差爲5得到(10,5)

4、由10減5,差爲5得到(5,5)

5、最後得最大公約數5

import java.util.Scanner;

public class Gcd2 {
    //更相減損法
    // 1、先判斷兩個數是否相等,如果相等,即爲最大公約數
    // 2、判斷兩個數是否是偶數,如果是偶數,將兩者進行移位運算
    // 3、用較大的數減較小的數,將差和較小數繼續重複運算,直至兩數相等

    public static int getGcd2(int n,int m) {
        if (n == m) {
            System.out.println(String.format("GCD(%d,%d)",n,m));
            return n;
        }

        if((n%2 == 0) && (m%2 == 0)){
            System.out.println(String.format("GCD(%d,%d)",n>>1,m>>1));
            return 2 * getGcd2(n>>1,m>>1);
        }else{
            int max = Math.max(n,m);
            int min = Math.min(n,m);
            int difference = max - min;
            System.out.println(String.format("GCD(%d,%d)",max,min));
            System.out.println(String.format("%d - %d = %d",max,min,difference));
            return getGcd2(min,difference);
        }
    }

    public static void main(String[] args) {
        System.out.println("Please input 2 numbers:");
        Scanner sc = new Scanner(System.in);
        int num1 = sc.nextInt();
        int num2 = sc.nextInt();
        int result = getGcd2(num1,num2);
        System.out.println(String.format("%d 和 %d 的最大公約數是:%d",num1,num2,result));
    }

}

 運行結果如下:

Please input 2 numbers:
98 63
GCD(98,63)
98 - 63 = 35
GCD(63,35)
63 - 35 = 28
GCD(35,28)
35 - 28 = 7
GCD(28,7)
28 - 7 = 21
GCD(21,7)
21 - 7 = 14
GCD(14,7)
14 - 7 = 7
GCD(7,7)
98 和 63 的最大公約數是:7

第三種:Stein算法

更相減損法:操作 甲數 乙數 Stein算法:操作 甲數 乙數  
  98 63   98 63  
98-63=35 63 35 98是偶數,除以2 49 63  
63-35=28 35 28 都是奇數,63-49=14 49 14  
35-28=7 28 7 14是偶數,除以2 49 7  
28-7=21 7 21 49-7=42 42 7  
21-7=14 7 14 42是偶數,除以2 21 7  
14-7=7 7 7 21-7=14 14

7

 
7-7=0 7 0 14是偶數,除以2 7 7  
      7-7=0 7 0  

更相減損法有點類似於求最大公約數的Stein算法。在更相減損法中,若兩個是偶數則同除以2,結果乘以2。

如果增加一個判斷,若爲一奇一偶則偶數除以2,結果不變,若爲兩個奇數才相減,這樣就變成了計算大整數最大公約數的非常好的一個算法,Stein算法。

import java.util.Scanner;

public class Gcd1 {
    // 計算輸入的兩個整數的最大公約數
    // Stein算法

    public static int getGcd1(int m,int n){
        int difference;

        // 判斷兩個數是否相等,如果相等,則返回最終結果。
        if(m == n ){
            System.out.println(String.format("GCD(%d,%d)",m,m));
            return m;
        }
        // 判斷兩個數是否爲0
        if(m == 0){
            System.out.println(String.format("GCD(%d,0)",n,0));
            return n;
        }
        else if (n == 0) {
            System.out.println(String.format("GCD(%d,0)",m,0));
            return m;
        }

        if((m % 2 == 0) && (n % 2 == 0)) {
            System.out.println(String.format("2*GCD(%d,%d)",m>>1,n>>1));
            return 2 * getGcd1(m >> 1,n >> 1);
        }else if((m % 2 == 0) && (n % 2 !=0)) {
            System.out.println(String.format("GCD(%d,%d)",m>>1,n));
            return getGcd1(m >> 1,n);
        }else if((n % 2 == 0) && (m % 2 != 0)) {
            System.out.println(String.format("GCD(%d,%d)",m,n>>1));
            return getGcd1(m,n>>1);
        }else{
            int max = Math.max(m,n);
            int min = Math.min(m,n);
            difference = max - min;
            System.out.println(String.format("GCD(%d,%d)",max,min));
            System.out.println(String.format("%d - %d = %d",max,min,difference));
            return getGcd1(min,difference);
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Please input 2 numbers:");
        int num1 = sc.nextInt();
        int num2 = sc.nextInt();
        int result = getGcd1(num1,num2);
        System.out.println(String.format("%d 和 %d 的最大公約數是:%d",num1,num2,result));

    }

}

運行結果如下: 

Please input 2 numbers:
98 63
GCD(49,63)
GCD(63,49)
63 - 49 = 14
GCD(49,7)
GCD(49,7)
49 - 7 = 42
GCD(7,21)
GCD(21,7)
21 - 7 = 14
GCD(7,7)
GCD(7,7)
98 和 63 的最大公約數是:7

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章