题目描述
高精度减法。
输入格式
两个整数 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;
}