n个数的最小公倍数

题目链接:n个数的最小公倍数

【题目描述】

求n个数的最小公倍数


【输入描述】
第一行一个数n(n<10)
下面n个数,integer范围内

【输出描述】
这n个数的最小公倍数

【样例输入】
5
6 3 5 4 2

【样例输出】
60

【数据范围及提示】

求出最大公约数后可用公式求最小公倍数


题目分析:

求解n个数的最小公倍数一般有两种做法:

1.分解质因数法:先把这几个数分解质因数,再把它们一切公有的质因数和其中几个数公有的质因数以及每个数的独有的质因数全部连乘起来,所得的积就是它们的最小公倍数.

12   15      8        9

12=2*2*3

15=3*5

8=2*2*2

9=3*3

其中12和8公有两个2,而12,15,9则公有质因子3,剩下的15独自有一个5,8独自有一个2,9独自有一个3

因此:最小公倍数为2*2*3*5*2*3=360

这种方法个人觉得适合人去算,并不适合计算机去计算。计算机更适合采用第二种方法。

2.公式法两两运用

假设现在要求最小公倍数的两个数为x,y,他们的最大公约数为p,最小公倍数为q。则x*y=p*q,也就是说只要求得两个数的最大公约数就可求得这两个数的最小公倍数。

但是题目中要求的是n个数的 最小公倍数,这里只需要用最小公倍数代替原来的两个数即可。

例如:12      15        8         9

第一步:求得12和15的最小公倍数为60 

第二部:求得60和8的最小公倍数为120

第三步:求得120和9的最小公倍数为360

所以,原问题转换为求两个数的最大公约数。最大公约数有几种求法,第一种对于小整数的辗转相除,大整数用辗转相减,还有优化版本的辗转相减法,这里给定数字范围为int因此直接采用辗转相除法。

辗转相除求最大公约数O(lgn)

递归写法:
int gcd(int a,int b){
	if(b==0)
		return a;
	else
		return gcd(b,a%b);
}
非递归写法:
int gcd(int a,int b){
	int c;
	while(b){
		c=a;
		a=b;
		b=c%b
	}
	return a;
}
利用x*y=q*p得到最小公倍数q=x*y/p;

完整代码 O(nlg(max{arr})):

#include<iostream>
using namespace std;
int arr[11];
int gcd(int a,int b){//两个方法任选一个
	if(b==0)
		return a;
	else
		return gcd(b,a%b);
}
int getGcd(int a,int b){
	int c;
	while(b){
		c=a;
		a=b;
		b=c%b;
	}
	return a;
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>arr[i];
		if(i!=1){
			arr[i]=arr[i-1]/getGcd(arr[i-1],arr[i])*arr[i];
		}
	}
	cout<<arr[n]<<endl;
} 

存在问题:

1.如果直接使用x*y/p存在溢出的风险
2.使用x/p*y可一定程度上避免溢出,但是依然不能完全规避;例如x=2^31-1,y=2,因此这里建议采用long  long   int;当然oj中给出的测试数据并没有出现溢出的情况,使用上面的代码依然能够AC


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值