歐幾里德算法
歐幾里德算法又稱為輾轉相除法,用於計算兩個非負整數的最大公因數。其偽代碼如下:
gcd(a, b) //要求a>=b if(b == 0) return a return gcd(b, a % b)
結果的正確性源於a與b的最大公約數c也是a%b的公共約數。原因很簡單,a%b=a-kb=ic-kjc=(i-kj)c,故a%b能整除c。設p為b和a%b的最大公約數,由於a=kb+a%b=xkp+yp=(xk+y)p,因此p能被a整除,因此p也是a與b的最大公約數,因此可以保證c>=p>=c,故p=c。
再不考慮遞歸的情況下,gcd的時間復雜度為O(1),而每次遞歸調用都會使得兩個傳入參數a與b中較大者減少一半以上(a%b<=min{a-b,b}),因此遞歸最多發生O(log2(a)+log2(b))=O(log2(ab))次,總的時間復雜度為O(log2(ab)),空間復雜度主要集中在遞歸,同樣也是O(log2(ab))。
應用
場景1
對於自然數a與b,有時候我們需要求解能使得x*(a/b)為整數的最小自然數x。我們可以將式子改寫為x*((a/c)/(b/c)),其中c是a與b的最大公約數,由於a/c與b/c沒有公約數,即二者互質,因此由算術基本定理知x能整除b/c,即x可以取值b/c,2b/c,...。當我們選取b/c作為x值時,式子的值為x*(a/b)=a/c,為整數,因此b/c即為我們要求的值。
場景2
設z是x與y的最大公約數,要求讓ax+by=z成立的某組可能的a與b的取值,也可以通過歐幾里德算法實現。
若x與y中有至少一者為0時,我們只需要取非0元素的系數為1,就可以得到一組解。而當x=y時只需要令a,b中任意一個為1另外一個為0即可得到所求值。之后均認為x>y>0。若我們已知ny+m(x%c)=c成立,則進行如下推導:$$ ny+m\left(x\%y\right)=z $$ $$ \Rightarrow ny+m\left(x-y\cdot\lfloor\frac{x}{y}\rfloor\right)=z $$ $$ \Rightarrow m\cdot x+\left(n-m\cdot\lfloor\frac{x}{y}\rfloor\right)\cdot y=z $$因此我們就得到了一組可行的a與b的值。
到此我們可以使用遞歸的思路求解a與b:
coe(x, y) //認為x>y if(y == 0) return (1, 0) n, m = coe(y, x % y) return (m, n - m * floor(x / y))
對於已知的一組式子ax+by=z,其中a,x,b,y,z均已知且z是x與y的公約數,希望找到另外一對n,m使得nx+my=c成立且n是所有符合值中最小自然數,即我們希望銳化a的取值。首先我們分別令等式左右兩邊除以z,此時式子形如np+mq=1,其中p與q互質。而我們的目標是通過修改n和m的值使得等式成立且n為最小自然數,因此我們將n與m的變更值記作u與v(這里認為n尚未達到目標結果,即u與v均非0),則可得up+vq=0。由於p與q互質,因此u能整除q且v能整除p,u的值最小允許取-q和q,表示對n最小幅度的波動。我們可以按照n現有符號對n不斷加上q或-q,直到n成為最小的可行自然數。這里可以直接寫作n%q。因此我們知道了n%(y/z)是使得式子ax+by=z滿足的最小自然數。
要求ax+by=cz滿足的一組a與b的取值,且c是給定整數,可以先使用上面的方法取一對可行解n,m使得nx+my=z成立,之后兩端均乘上c得到cnx+cmy=cz,就得到一組可行系數。
