算法中的数学问题

1.最大公约数和最小公倍数

(1)最大公约数

正整数a与b的最大公约数是指a与b的所有公约数中最大的那个公约数,记为gcd(a,b),而求解最大公约数常用欧几里得算法(即辗转相除法)

欧几里得算法基于下面这个定理:
设a、b均为正整数,则gcd(a,b) = gcd(b,a%b)
可以看到,如果a<b,那么定理的结果就是将a和b交换,如果a>b,那么通过这个定理总可以将数据规模变小,并且减小的非常块,并且由0和任意正整数的最大公约数等于正整数本身,得到递归边界,即:
① gcd(a,0) = a
② gcd(a,b) = gcd(b,a%b)

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

(2)最小公倍数

正整数a与b的最小公倍数是指a与b的所有公倍数中最小的那个公倍数,一般用lcm(a,b)

最小公倍数的求解在最大公约数的基础上进行,当得到a和b的最大公约数d之后,可以马上得到a和b的最小工公倍数是ab/d(ab实际计算可能溢出,更好的写法是(a/d)*b)

这个公式通过集合可以很好理解,a和b的最大公约数即集合a与集合b的交集,而最小公倍数为集合a和集合b的并集,因此ab多算了一次公因子,因此需要多除一次公因子
在这里插入图片描述

int MaxCommonMultiple(int a, int b)
{
	int d = MaxCommonDivisor(a, b);
	return (a / d) * b;
}

2.分数相关

所谓分数的四则运算是指,给定两个分数的分子和分母,求它们加减乘除的结果

(1)分数的表示和化简

分数的表示

对一个分数来说,最简洁的写法就是写成假分数的形式用结构体保存。
由于分数的乘法和出发过程中可能是分子或分母超过int型表示范围,一般情况下用long来存储

struct Fraction
{
	long up,down;  //分子、分母
};

其中需要对这种表示定制三项规则:
① 使分母为非负数,如果分数为负,令分子为负
② 如果该分数恰为0,规定分子为0,分母为1
③ 分子和分母没有除了1以外的公约数(最简)

分数的化简

分数的化简即执行上述三项规则:
① 如果分母down为负数,那么令分子up和donw都变味相反数
② 如果分子up 为0,那么令分母down为1
③ 约分:求出分子绝对值与分母绝对值的最大公约数,然后令分子分母同时除以d

void reduction(Fraction& result)
{
	//第一项规则
	if (result.down < 0)
	{
		result.up = -result.up;
		result.down = -result.down;
	}
	//第二项规则
	if (result.up == 0)
		result.down = 1;
	//第三项规则
	int d = MaxCommonDivisor(result.up, result.down);
	result.up /= d;
	result.down /= d;
}

(2)分数的四则运算

按正常的分数四则运算计算即可,注意结果的化简

3.素数(质数)

素数又称质数,是指除了1和本身之外,不能其他数整除的一类数

(1)素数的判断

一个素数要判断为素数,需要判断n是否能被2,3,…n-1中的一个整除。这样的判定方法没有问题,时间复杂度为O(n),但是在很多题目中,判断素数只是整个算法中的一个部分,这时候O(n)实际上有点大,有没有更简单的方法呢?有的。

我们假设n存在约数,设为K,则k*(n/K)= n。且K和n/k分布在sqrt(n)的两端,所以我们只需要判断2,3,4…sqrt(n)向下取整,就可以了,时间复杂度为O(√n)

bool isPrime(int n)
{
	int sqr = (int)sqrt(n*1.0);
	for (int i = 2; i <= sqr; ++i)
	{
		if (n % i == 0)
			return false;
	}
	return true;
}

(2)素数表的获取

素数表的获取即对1~n进行枚举,判断每个数是否是素数,如果是素数则加入素数表中国,时间复杂度为(n√n))

4.质因子分解

所谓质因子分解是指将一个正整数n写成一个或多个质数的乘积的形式
由于每个质因子都可以不止出现一次,因此不妨定义结构体factor,用来存放质因子及其个数:

struct factor
{
	int x,cnt;  //x为质因子,cnt为其个数
}fac[10];

前面提到过,对一个正整数n来说,如果它存在1和本身之外的因子,那么一定是在sqrt(n)的左右成对,而这里把这个结论用在“质因子”上面,会得到一个强化结论:对一个正整数来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其余质因子全部小于等于sqrt(n)。得到下面思路
① 枚举1~sqrt(n)范围内的所有质因子p,判断p是否是n的因子

  • 如果p是n的因子,那么给fac数组中增加质因子p,并初始化其个数为0。然后,只要p还是n的因子,就让n不断除以p,每次操作令p的个数加1,直到p不再是n的因子为止。
  • 如果p不是n的因子,就直接跳过
    ② 如果在上面步骤结束后n仍然大于1,说明n有且仅有一个大于sqrt(n)的因子,这是需要把这个质因子加入fac数组,并令其个数为1
int  FactorPrime(factor fac[],int num)
{
	int sqr = (int)sqrt(num * 1.0);
	memset(fac, 0, sizeof(factor) * 10);
	int k = 0;
	for (int i = 2; i <= sqr; ++i)
	{
		if (num % i != 0)
			continue;
		fac[k].x = i;
		while (num % i == 0)
		{
			num /= i;
			fac[k].cnt++;
		}
		++k;
	}
	if (num != 1)
	{
		fac[k].x = num;
		fac[k].cnt = 1;
	}
	return k;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值