关键词:高精度减法、vector(容器)
地位:算法竞赛普遍涉及,在笔试、面试是一个比较重要的考点。
高精度的很多知识点在高精度加法已经介绍过了,高精度的加减乘除有很多相同之处。即便如此,文中依然保留两种代码:用vector实现的高精度、数组实现的高精度。
(高精度减法压位用的太少了)
高精度加法的链接就在下方,还没了解高精度的读者可以先了解这篇文章:
7.AcWing791.高精度加法(AcWing算法基础课二刷)_浩子诚的博客-CSDN博客
高精度减法依然可以采用竖式计算的方法解决。此时保证函数中的A一定大于等于B(之后会解释原因),从个位开始相减。如下图所示:在第i位中,A-B的结果是。如果这个式子为负数,那么要想前一位借1,即加上10;t表示后一位是否借1,所以t只有1和0两种情况。实现方法和高精度加法基本一致,也是使用vector<int>来模拟高精度。
那么如何判断A-B的关系?此时我们可以先比较A和B字符串的“大小”(不可以直接用字典序),然后再判断A和B的关系。我们是这样判断的:如果A和B位数相等,则判断A和B的字典序;如果不相等,那当然是位数大的数字较大。如果A小于B,则先输出负号,再转化为B-A。这就是上述操作中A一定大于B的原因。
大家可以结合下图(y总算法基础课的高精度减法)来理解上述的两段话。
下面是基于vector容器实现的高精度减法模板:
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
bool cmp(string a,string b)//判断a是否大于等于b
{
if(a.size()!=b.size()) //先判断a和b的位数关系
return a.size()>b.size();
else//位数相同根据字典序判断
{
if(a>=b) return true;
else return false;
}
}
//两个高精度整数的减法
vector<int> sub(vector<int> &a,vector<int> &b)
{
int t=0;//t表示是否借1
vector<int> ans;//ans逆序(个位下标是0)存储高精度整数
for(int i=0;i<a.size();i++)//从个位加到最高位
{
//让这一次的t成为ai-bi-t(上一次的t)
//ai-bi-t可以先让ai-t,在判断bi是否有数
t=a[i]-t;
if(i<b.size()) t-=b[i];//b的第i位存在数字
ans.push_back((t+10)%10);//t可能为负数,加上10
//向前一位借1,之后模10作为个位数存储
if(t<0) t=1;//如果t<0说明向前借了1,下一次的t是1
else t=0;//否则没有借0,下一次不需要减1
}
//去除前导零操作,如果最高位(容器末尾)是0,则需要删除
//直到数组长度剩下1(即结果是0)或者没有前导零了为止
while(ans.size()!=1&&ans.back()==0) ans.pop_back();
return ans;//记得要返回vector容器
}
int main()
{
string A,B;
cin>>A>>B;
vector<int> a,b,c;
//字符串转vector存储
for(int i=A.size()-1;i>=0;i--)
a.push_back(A[i]-'0');
for(int i=B.size()-1;i>=0;i--)
b.push_back(B[i]-'0');
if(cmp(A,B))//判断A是否比B大(或相等)
{
//如果是,计算a-b
c=sub(a,b);
}
else//如果不是
{
//输出负号、之后计算b-a
printf("-");
c=sub(b,a);
}
//逆序输出高精度
for(int i=c.size()-1;i>=0;i--)
printf("%d",c[i]);
return 0;
}
接下来展示手写数组模拟高精度减法(可以通过792题):
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;//题目的位数最多是100000位
char A[N],B[N];
int a[N],b[N],c[N];
bool cmp(char a[],char b[])
{
if(strlen(a)==strlen(b))//位数相同
return strcmp(a,b)>=0;//strcmp比较两个数组的字典序
//大于0,A字典序大;等于0,字符串相等;小于0,B字典序大
else return strlen(a)>strlen(b);//否则比较位数
}
int main()
{
scanf("%s%s",A,B);
if(!cmp(A,B))
{
swap(A,B);//swap也可以交换数组
printf("-");
}
int alen=strlen(A),blen=strlen(B);
//字符转整数数组存储
for(int i=0,j=alen-1;i<alen;i++,j--)
a[i]=A[j]-'0';
for(int i=0,j=blen-1;i<blen;i++,j--)
b[i]=B[j]-'0';
//思想和用vector容器一样,就不赘述了
int clen=max(alen,blen);
int t=0;
for(int i=0;i<clen;i++)
{
t=a[i]-t;
if(i<blen) t-=b[i];
c[i]=((t+10)%10);
if(t<0) t=1;
else t=0;
}
//删除前导0操作
while(c[clen-1]==0&&clen!=1) clen--;
for(int i=clen-1;i>=0;i--) printf("%d",c[i]);
return 0;
}
用数组模拟稍微比vector要快一点。
参考链接/文献:
Ⅰ.AcWing——算法基础课,2019,闫学灿 活动 - AcWing
Ⅱ.AcWing792.高精度减法 活动 - AcWing
感谢您的支持