zoukankan      html  css  js  c++  java
  • 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,里面的一小段代表最大公约数,现在演示如何用辗转相除法求最大公约数。

      

      

  • 相关阅读:
    最新超详细VMware虚拟机安装完整教程
    Java网络编程 -- AIO异步网络编程
    Java网络编程 -- NIO非阻塞网络编程
    Java网络编程 -- BIO 阻塞式网络编程
    Java网络编程 -- 网络协议
    自定义FutureTask实现
    JDK容器类List,Set,Queue源码解读
    JDK容器类Map源码解读
    深入理解Java中的锁(三)
    深入理解Java中的锁(二)
  • 原文地址:https://www.cnblogs.com/qq2210446939/p/13399980.html
Copyright © 2011-2022 走看看