读取字符串的高精度数字,然后用int数组存上,通过最基础的每位加减乘除和进位等操作完成。
下方给出了所有的操作函数,注意函数的所有输入均为vector 的数组,并且数组存储是从数的低位开始存1000 = [0,0,0,1],和正常存储相反,这是为了便于操作。
791. 高精度加法
题目
791. 高精度加法 - AcWing题库
给定两个正整数,计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1 ≤ 整数长度 ≤ 100000
样例输入1
12
23
样例输出1
35
思路
将输入数据按位存储到数组A[] B[], 然后从低位开始遍历相加,大于10进位
// O(n)
// C = A + B, A >= 0, B >= 0
// A B C 数组是从数的低位开始存1000 = [0,0,0,1]
vector<int> add(const vector<int> &A, const vector<int> &B)
{
if(A.size() < B.size()) return add(B, A); // 保证A数组长
vector<int> C;
int carry = 0; // 进位
int i;
for(i = 0; i < B.size(); i++)
{
carray = A[i] + B[i] + carray;
C.push_back(carray % 10);
carray /= 10;
}
for(i; i < A.size(); i++)
{
carray = A[i] + carray;
C.push_back(carray % 10);
carray /= 10;
}
if(carray) C.push_back(carray);
return C;
}
AcWing 792 高精度减法
题目
792. 高精度减法 - AcWing题库
给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的差。
数据范围
1≤整数长度≤105
输入样例:
32
11
输出样例:
21
思路
输入输出方式与高精度加法一样,区别在于减法当前位的结果应该+10之后再%10,判断当前结果如果小于0,应该将当前临时变量变为1,下次计算时减去之前借的1。 注意结尾要去除前导0.
注意控制输入 sub的是A >= 0, B >= 0,A B C 数组是从数的低位开始存1000 = [0,0,0,1],A > B, 注意一定是大减小。
为了实现大减小,可以用cmp函数。
// O(n)
// C = A + B, A >= 0, B >= 0
// A B C 数组是从数的低位开始存1000 = [0,0,0,1]
// A > B, 注意一定是大减小
vector<int> sub(const vector<int> &A, const vector<int> &B)
{
vector<int> C;
int carry = 0;
for(int i = 0; i < A.size(); ++i)
{
carry = A[i] - carry;
if(i < B.size()) carry -= B[i];
C.push_back((carry + 10) % 10);
// carry<0 表示从上一位借了一位
if(carry < 0) carry = 1;
else carry = 0;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
// 保证sub是大减小,判断谁打
// A >= 0, B >= 0
// A B 数组是从数的低位开始存1000 = [0,0,0,1]
bool cmp(const vector<int> &A, const vector<int> &B)
{
if(A.size() != B.size()) return A.size() > B.size();
for(int i = A.size(); i ; i++) // 从高位开始比较
if(A[i] != B[i]) return A[i] > B[i];
return true;
}
AcWing 793 高精度乘法
793. 高精度乘法 - AcWing题库
题目
给定两个非负整数(不含前导 0) A 和 B,请你计算 A×B 的值。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共一行,包含 A×B 的值。
数据范围
1≤A的长度≤100000,
0≤B的长度≤10000
输入样例:
2
3
输出样例:
6
思路
- 高精度乘低精度
将高精度数组的每一位数乘以低精度数后进位,最终得到的进位再一直向高精度数组延伸填充。注意去除前导零。
// O(nm)
// C = A * B, A >= 0, B >= 0
// A 数组是从数的低位开始存1000 = [0,0,0,1]
// 高精度乘低精度
vector<int> mul(const vector<int> &A, const int b) {
vector<int> C;
int carry = 0;
for (int i = 0; i < A.size() || carry; i++) {
if (i < A.size()) carry += A[i] * b;
C.push_back(carry % 10);
carry /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
- 高精度乘高精度 43. 字符串相乘
二层循环乘累加起来,注意递进结果起始位置。在来一个循环遍历结果数组进位。注意去除前导零。
// O(nm)
// C = A * B, A >= 0, B >= 0
// A B 数组是从数的低位开始存1000 = [0,0,0,1]
// 高精度乘高精度
vector<int> mul2(const vector<int> &A, const vector<int> &B) {
vector<int> C(A.size() + B.size());
for(int i = 0; i < A.size(); i++)
{
for(int j = 0; j < B.size(); i++)
{
C[i + j] += A[i] * B[i];
}
}
int carry = 0;
for(int i = 0; i < C.size(); i++){
carry = C[i];
C[i] = carry % 10;
carry /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
AcWing 794 高精度除法
Acwing 794 高精度除法
题目
给定两个非负整数(不含前导 0) A,B,请你计算 A/B 的商和余数。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤100000,
1≤A的长度≤10000,
B 一定不为 0
输入样例:
7
2
输出样例:
3
思路
- 高精度除以低精度
从被除数A的高位开始,即A.size() - 1尝试除以b得到每一个商位置的值,循环,将上一次除以的余数结果*10 + 当前A[i]存的被除数 得到此位置的被除数,一直循环除到结束。其实这个过程就是竖式的除法原理。
// O(n)
// A / b = C ... r, A >= 0, b > 0
// A C 数组是从数的低位开始存1000 = [0,0,0,1]
pair<vector<int>, int> div(const vector<int> &A, int b)
{
vector<int> C;
int r = 0; // 余数
for(int i = A.size() - 1; i; --i)
{
r = 10 * r + A[i]; // 向低一位移动除法
C.push_back(r / b); // 存的时候从高位开始存
r %= b; // 这一部分除完之后得到的余数,下一次移动后继续除法
}
reverse(C.begin(), C.end()); // 翻转为从低位开始存
while (C.size() > 1 && C.back() == 0) C.pop_back(); // 去除前导零
return {C, r};
}
- 高精度除以高精度
对于两个高精度数,类似高精度除以低精度,还是从A的高位开始尝试除以整个B,这时候A的高位类似上面 r = 10 * r + A[i]; 截取出来一部分很麻烦,可以直接用整个A,让B来对齐,即B向高位移动x位即可,这时候A/B一定只有B的高位非0值的正在除。然后循环移动的x位直到0位,如下图即可计算出。
其中A/B的试除通过循环减直到A < B的时候即可,减成功的次数就是该位的商。循环到最后余下的数即余数
// O((n-m)*n)
// A / B = C ... R, A >= 0, b > 0
// A B C数组是从数的低位开始存1000 = [0,0,0,1]
pair<vector<int>, vector<int>> div2(vector<int> A, const vector<int> &B) {
vector<int> C, R; // 商 余数
int c_size = A.size() - B.size(); // 商的长度
c_size = c_size > 1 ? c_size : 1; // 防止A比B小短,结果数组最小长度为1
C.resize(c_size, 0);
// 枚举补0的个数,即将B低位补零使得和每次被除数A的高位对齐
// eg2: 11111 / 11 --> 11111 / 11000 --> 0111 / 110 --> 01 / 11
for(int i = c_size; i >= 0; --i)
{
vector<int> Bp(i, 0); // 前面补i个0
for(int x : B) Bp.push_back(x); // Bp后面是B
// 当A >= Bp 时候就一直通过减来得到除的结果
int c = 0;
while(cmp(A, Bp))
{
c++;
A = sub(A, Bp);
}
C.push_back(c);
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); // 去除前导零
R = A;
return {C, R};
}