洛谷 P2142 高精度减法

题目描述

高精度减法。

输入格式

两个整数 a,b(第二个可能比第一个大)。

输出格式

结果(是负数要输出负号)。

思路(debug的艰难过程)

前天刚刚学会了高精度加法,其实高精减的思路和加法类似,只是多加了借位的操作。基本步骤还是反向构造数组->模拟竖式减法->倒序输出。但有两个点需要注意:

1.由于a,b的大小关系不确定,所以我的思路是统一转换成a>b的模式,若a<b则交换a,b并输出负号。一开始比较a和b的时候我是这样做的:

if(strcmp(s1,s2)<0)

然后有3个点WA了,看了测试点样例(30141,8160)后发现只用strcmp函数完全不行,因为strcmp函数是自左向右逐个字符比较,出现不同的字符则返回s1[i]-s2[i]的值。在这个样例中s1[0]=='3',s2[0]=='8',strcmp(s1,s2)<0,需要交换两字符串,然而观察发现a>b,并不需要交换。看了dalao的代码才发现这个比较方法如此巧妙:

if(strlen(s1)<strlen(s2)||strlen(s1)==strlen(s2)&&strcmp(s1,s2)<0)

2.输出答案时,由于答案的位数在strlen(s1)~1之间,我们将输出的范围定在c[1]-c[strlen(s1)],那么如果c的位数小于strlen(s1),答案就会出现前导0,这时我们就需要解决消去前导0的问题。我的想法是,第一次出现非0数时进行标记,若c[i]==0&&flag则证明该0不是前导0,进行输出:

int flag=0;
	for(int i=strlen(s1);i>0;i--){
		if(c[i]!=0){
			flag=1;printf("%d",c[i]);
		}
		if(c[i]==0&&flag) printf("%d",c[i]);
	}

还有一种情况没有解决:如果a==b,只需要输出0怎么办。上面代码的flag可以轻松解决这个问题:如果循环结束时flag==0,那么证明答案中只有0,也就是a==b,此时输出0即可。

if(flag==0) printf("0");

完整代码:

#include<stdio.h>
#include<string.h>
int main(){
	char s1[11000],s2[11000];//约定a>b 
	int a[11000]={0},b[11000]={0};
	scanf("%s %s",s1,s2);
	if(strlen(s1)<strlen(s2)||strlen(s1)==strlen(s2)&&strcmp(s1,s2)<0){//巧妙比较两数大小,不能简单地用字符串比较函数 
		char tem[11000];
		strcpy(tem,s1);
		strcpy(s1,s2);
		strcpy(s2,tem);
		printf("-");
	}
	for(int i=1;i<=strlen(s1);i++){
		a[i]=s1[strlen(s1)-i]-'0';
	}
	for(int i=1;i<=strlen(s2);i++){
		b[i]=s2[strlen(s2)-i]-'0';
	}
	int c[11000]={0};
	for(int i=1;i<=strlen(s1);i++){
		if(a[i]-b[i]<0){
			a[i]+=10;a[i+1]--;
		}
		c[i]=a[i]-b[i];
	}
	int flag=0;
	for(int i=strlen(s1);i>0;i--){
		if(c[i]!=0){
			flag=1;printf("%d",c[i]);
		}
		if(c[i]==0&&flag) printf("%d",c[i]);
	}
	if(flag==0) printf("0");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值