辗转相除法证明

        今天做面试题,又遇到了求两个数的最大公约数(gdc)问题,题虽简单,但还是通过比划了一两个例子,才想起了辗转相处的思路来。

        (1) r = a%b 

        (2)r != 0, a = b,b = r 转(1)

        (3)r = 0 ,return b

        几行代码就能搞定,但记住这些步骤,就如同记住了某个库函数。遇到相同的问题我们能很快处理,此时知识与问题之间是一对一的关系。因不了解其原理,大脑里总有一个问号,why it does work?。如果原理性的东西不高明白,那么我们就无法做到举一反三。就如同一个强大的武器仅发挥了10%的作用,还90%被我们给浪费了。就如同库函数,不了解其源码,处理错就不知该如何下手,我们就无法回答向 它在什么时候使用,能处理什么问题,在什么情况下效率最高这类问题。

于是开始寻找辗转相处法的证明:

        该方法将 gdc(a,b),转化为gdc(b,r),其中r=a%b,因此我们要证明的就是gdc(a,b)=gdc(b,r)

        证明:令c = gdc(a,b),k = a/b,r = a%b;设 a = mc, b = nc;

        =>r = mc - knc 

        =>r = (m - kn)c=>c 为 r的因子 (1)

        接着证明c为b,r的最大公因子,即 m-kn 与 n 互质,用反证法

        假设 m-kn 与 n 存在公因子 d,则 r = xdc, b = ydc => a = kydc + xdc = (ky+x)dc

        =>  gdc(a,b) = dc 与题设矛盾故  m-kn 与 n 互质。(2)

        综合(1)、(2)可知 c 为b ,r的最大公约数

        证毕。  

        现在脑海中的困惑没了,这个feel,很爽...

        越来越明显的感到,曾经费很大精力搞明白的东西,过一段时间再看又想不起来了,我也一直再寻觅一种跳出这种窘境的办法,好的办法还没发现,但有些基本规律是不变的。1、得之越难,印象越深。 2、解题的方法,比具体的步骤更重要。 3、问题的本质,比现象更重要。不仅要通过试错找到正确的路径,更要明白为什么这条路正确。否则,稍有变化,又要不断的试错,很痛苦,很耗时。

#include <iostream>

using namespace std;
/*
** 求两个数的最大公约数
**	in: a 
**  <span style="white-space:pre">	</span>in: b
**	out: gdc 最大公约数 -1 error
*/

int gdc(int a, int b)
{
	if(a == 0 || b==0 ){
		cout << "error inupt 0\n";
		return -1;
	}
	int out,r,temp;
	out = a > b ? a : b;
	r = a > b ? b : a;
	while (r)
	{
		temp = r;
		r = out%r;
		out = temp;
	}
	return out;
}

        辗转相除法不必关心a,b谁更大,因此上面代码中判断a,b大小的部分可以省略,《编程之美》给出了十分优雅的代码

int gcd(int a, int b)
{
	return (!b) ? a : gcd(b,a%b);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值