• gcd详解


    简述

      给你两个数a和b,要求求出a和b的最大公约数。为了解决这个问题,我们可以想到很多方法,穷举法,辗转相除法,更相减损法等。这里我们详解介绍穷举法和辗转相除法。

    问题描述

      我们把问题用数学语言进行描述:已知整数a和b,求一数k满足a%k==0&&b%k==0,且k要尽可能大。

    穷举法

      因为k小于等于a和b,所以我们可以从a和b选一个数开始进行穷举,这里我们选择较小的那个数,因为k一定小于等于较小那个数。

    int gcd(int a,int b){
        int num=min(a,b);
        for(int i=num;i>=1;i--){
            if(a%i==0&&b%i==0) 
                return i;
        }
    }

      这个算法的时间复杂度为O(min(a,b)),因为最多会执行min(a,b)次,当a和b特别大的时候,这个程序是很慢的。

    辗转相除法

      辗转相除法又称欧几里得算法,这是我们小学就学过的算法,古希腊数学家欧几里德在其著作《The Elements》中最早描述了这种算法,所以被命名为欧几里德算法,又在九章算术里描述为辗转相除法。

      我们现在将求a和b两个数的最大公约数定义为函数gcd(a,b)。

      辗转相除法的算法思想是,gcd(a,b)=gcd(b,a%b),当b为0时gcd(a,b)为a。不断重复gcd(a,b)=gcd(b,a%b)则b终会等于0,最后求出等式的结果。

      例如我们现在要求gcd(9,12),则可以写出以下的过程:

      gcd(9,12)=gcd(12,9%12)=gcd(12,9)=gcd(9,12%9)=gcd(9,3)=gcd(3,9%3)=gcd(3,0)=3

    int gcd(int a,int b){
        if(b==0) return a;
        return gcd(b,a%b);
    }

      辗转相除法的时间复杂度为O(logn),证明省略。

    辗转相除法的证明

      为什么gcd(a,b)=gcd(b,a%b)呢?

      我们设gcd(a,b)=k,r=a%b。

      可得a=sk,b=tk,s和t互质,a=bq+r,q为正整数

      左带入右得sk=tkq+r,整理得r=k(s,tq),所以k也是r的因子。

      我们可以将求gcd(a,b)的过程理解为求a和b两个因数集合里最大的相同数,将gcd(a,b)=gcd(b,a%b)过程可以理解为使用一个r代替b,使得b变小但r的因数集里包含最大公约数k,一直减小到0时,当时的a就是我们求的k了。

      我们开看一张gif图,两条线段的长度分别代表a和b,里面的一小段代表最大公约数,现在演示如何用辗转相除法求最大公约数。

      

      

  • 相关阅读:
    第4章 Java并发编程的基础
    第3章 Java内存模型
    Ajax请求重复发送问题
    React的Hook函数之React.useState()、React.useEffect()
    Ajax GET请求和POST请求的基本操作
    使用pubsub-js来做消息的订阅和发布
    React配置代理解决跨域问题
    React中的函数式组件和类式组件
    JSX语法规则
    Hello React!
  • 原文地址:https://www.cnblogs.com/qq2210446939/p/13399980.html
Copyright © 2020-2023  润新知