《算法笔记》学习记录 Part 2

第五章 数学问题:

5.1 简单数学问题:

PAT-B 1003. 我要通过!(20) 
PAT-B 1019. 数字黑洞 (20) 
PAT-B 1049. 数列的片段和(20) 


5.2 最大公约数与最小公倍数:

    最大公约数的两种写法,运用的原来是欧几里得算法(即辗转相除法)

int gcd(int a,int b){
	return !b?a:gcd(b,a%b);
}
int gcd(int a,int b){
	if(b==0) return a;
	else return gcd(b,a%b);
}

最小公倍数一般用 lcm(a,b) 表示,如果d为a和b的最大公约数,则最小公倍数为ab/d,

为了避免越界,最小公倍数最恰当的写法是a/d*b。由于d是a和b的最大公约数,因此a/d一定可以整除

    

5.3 分数的四则运算:详细代码

5.4 素数:

Eratosthenes筛法求素数(埃氏筛法)

PAT-B 1007. 素数对猜想 (20) 

PAT-B 1013. 数素数 (20) 

5.5 质因子分解:

      对于一个正整数n来说,如果它存在1和它本身之外的银子,那么一定是在sqrt(n)的左右成对出现。如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其它质因子全部小于等于sqrt(n)

    思路:

step1:枚举1~sqrt(n)范围内的所有质因子p,判断p是否为n的因子,如果是,就给fac数组中增加质因子p,并初始化个数为0,然后只要p还是n的因子,就让n不断除以p,每次操作令p的个数加1,直到p不再是n的因子为止

struct factor{
	int x,cnt; //x为质因子,cnt为个数
}fac[10];
	if(n%prime[i]==0){	//prime[i]是质数表数组
		fac[num].x = prime[i]; //如果prime[i]是质因子,记录它
		fac[num].cnt = 0;
		while(n%prime[i]==0){	//计算出质因子prime[i]的个数
			fac[num].cnt++;
			n/=prime[i];
		}
		num++;
	} //如果p不是n的因子,直接跳过

step2:如果上面步骤结束后n仍然大于1,说明n有且仅有一个大于sqrt(n)的质因子(也有可能是n本身),这时需要把这个质因子加入fac数组,并令其个数为1

    if(n!=1){
	fac[num].x = n;
	fac[num++].cnt = 1;
    }

5.6 大整数运算

PAT-B 1017. A除以B(20)

5.6.1 大整数的储存

    使用数组,数组中的每一位就代表了存放的每一位,而为了方便随时获取大整数的长度,一般都会定义一个int型变量len来记录其长度,并和d数组成结构体,并在结构体内部加上构造函数

struct bign{
	int d[1000];
	int len;
	bign(){
		memset(d,0,sizeof(d));
		len=0;
	}
};

输入大整数时,一般都是先用字符串读入,然后把字符串另存为至bign结构体。由于使用char数组进行读入时,整数的高位会变成数组的低位,而整数的低位会变成数组的高位,因此为了让整数在bign中顺位存储,需让字符串倒着赋给d[]数组

bign change(char str[]){
	bign a;
	a.len = strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i] = str[a.len-i-1] - '0';
	}
	return a;
}

如果要比较两个bign变量的大小:先判断长度,不相等则长的大;若相等,则从高位到低位进行比较,知道出现某一位不等

5.6.2 大整数的高精度加法

这样写法的条件是两个对象都是非负整数,如果有一方是负的,可以去掉负号,做高精度减法

bign add(bign a,bign b){
	bign c;
	int carry=0;		//carry是进位
	for(int i=0;i<a.len || i<b.len;i++){
		int temp = a.d[i]+b.d[i]+carry; //两个对应位与进位相加
		c.d[c.len++] = temp%10; //个位数为该位的结果
		carry = temp/10;
	}
	if(carry!=0){	//如果最后进位不为0,则直接赋值给结果的最高位
		c.d[c.len++] = carry;
	}
	return c;
}
5.6.3 大整数的高精度减法
//默认大减小
bign sub(bign a,bign b){
	bign c;
	for(int i=0;i<a.len || i<b.len;i++){
		if(a.d[i]<b.d[i]){
			a.d[i+1]--;
			a.d[i]+=10;
		}
		c.d[c.len++] = a.d[i] - b.d[i];
	}
	while(c.len-1>=1 && c.d[c.len-1]==0){
		c.len--;   	//去除高位的0,同时至少保留一位最低位
	}
	return c;
}
5.6.4 高精度与低精度的除法
bign divide(bign a,int b,int& r){ //高精度除法,r为余数
	bign c;
	c.len = a.len;//被除数的每一位和商的每一位是一一对应的
	for(int i=a.len-1;i>=0;i--){
		r = r*10 + a.d[i];
		if(r<b) c.d[i]=0;	//不够除,商0
		else{	//够除
			c.d[i]=r/b;	//商
			r = r%b;		//新余数
		}
	}
	while(c.len-1>=1 && c.d[c.len-1]==0){
		c.len--;		//去除高位0
	}
	return c;
}
5.6.5 高精度与低精度的乘法
bign multi(bign a,bign b){
	bign c;
	int carry = 0;
	for(int i=0;i<a.len;i++){
		int temp = a.d[i]*b+carry;
		c.d[i]=a.d[i]*b+carry;
		carry=temp/10;
	}
	while(carry!=0){
		//和加法不一样,乘法的进位可能不止一位,因此用while
		c.d[c.len++] = carry%10;
		carry/=10;
	}
	return c;
}








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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪突猛进!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值