0
点赞
收藏
分享

微信扫一扫

【算法基础课模板笔记+注释】 基础算法05 --- 高精度(大整数)

guanguans 2022-02-17 阅读 76

声明

本文资料参考acwing算法基础课
地址:https://www.acwing.com

概述

  1. 解决问题:求大整数的各种运算
  2. 时间复杂度为O(size)

大整数表示

使用string读入,使用一个vector数组存储,从0位开始分别表示大整数由低到高的位上数字。

// 输入
string a;
vector<int> A;
cin >> a;
for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0');
// 输出
for (int i = A.size() - 1; i >= 0; i -- ) cout << A[i];

加法模板记忆

这个模板分为6个部分:

  1. 保长 :确保A比B长
  2. :初始化结果C和进位/求和位t
  3. 求和:每一轮加上A、B对应位
  4. 压位:把t % 10压入C
  5. 进位:把t / 10保留进位
  6. 判进位:结果的size可能比A大1,这样的话需要将进位位压入

加法

// AB求和返回一个vector
vector<int> add(vector<int> &A, vector<int> &B)
{
// 1保长
    if (A.size() < B.size()) return add(B, A);  // 确保A比B长
// 2初
    vector<int> C;  // 初始化结果数组
    int t = 0;  // 初始化累加或进位位
    for (int i = 0; i < A.size(); i ++ )
    {
// 3求和
        t += A[i];  // 首先加上A和B
        if (i < B.size()) t += B[i];  // 注意B的长度
// 4压位
        C.push_back(t % 10);  // 如果t是XY,把Y压入C
// 5进位
        t /= 10;  // 把X保留
    }
// 6判进位
    if (t) C.push_back(t);  // C的size可能比A大1,所以特判一下
    return C;
}

减法模板记忆

这个模板分为6个部分:

  1. 保号 :确保A>=B
  2. :初始化结果C和进位/求和位t
  3. 减法:t = A - t - B
  4. 压位:把(t+10) % 10压入C
  5. 借位:判t是否<0判断是否借位,用t保存
  6. 前导0:去除C的前导0

减法

// 比较A、B哪个大,返回A >= B
bool cmp(vector<int> &A, vector<int> &B)
{
    if (A.size() != B.size()) return A.size() > B.size();  // 不等长化为比长度
    for (int i = A.size() - 1; i >= 0; i -- )
        if (A[i] != B[i]) return A[i] > B[i];  // 等长的时候一次从高位比较,第一个不同位大小
            
    return true;  // 完全相同返回true
}
// 1A减B返回一个vector(前提是A>B)
vector<int> sub(vector<int> &A, vector<int> &B)
{

// 2初
    vector<int> C;  // 初始化结果
    int t = 0;
    
    for (int i = 0; i < A.size(); i ++ )
    {
// 3减法
        t = A[i] - t;  // A减去借位
        if (i < B.size()) t -= B[i];  // B存在的话,减去相应的B
// 4压位
        C.push_back((t + 10) % 10);  // 这时t保存了A - B - 借位的数,可能是负数,直接压入+10再%10(如果不够减借了位)
// 5借位
        if (t < 0) t = 1;  // 借位的话要把t置1
        else t = 0;  // 没借位置0
    }
		// 最后一次一定不用借位,因为A>=B
		// 把C.back()也就是数字的高位的0pop掉,注意只有一个的时候不要pop
// 6前导0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}

乘法模板记忆

这个模板分为5个部分:

  1. :初始化结果C和进位/求和位t
  2. 累加:t = t + A * b
  3. 压位:把t的最低位压入C
  4. 更新累加:用压入后剩余位覆盖t
  5. 前导0:去除C的前导0,实际上只有b为0才用去除前导零,但是保险起见可以去除

乘法

// A乘b返回一个vector
vector<int> mul(vector<int> &A, int b)
{
// 1初
    vector<int> C;
    int t = 0;
    
    for (int i = 0; i < A.size() || t; i ++ )  // 在A没有遍历完或t没有清空时继续循环
    {
// 2累加
        if (i < A.size()) t += A[i] * b;  // t累加A*b
// 3压位
        C.push_back(t % 10);  // 假设t为XYZ,把Z压入
// 4更新累加
        t /= 10;  // 用XY代替原来的t进行下一轮累加
    }
// 5前导0
    while (C.size() > 1 && C.back() == 0) C.pop_back();

    return C;
}

除法模板记忆

这个模板分为5个部分:

  1. :初始化结果C和进位/求和位t
  2. 临时被除数:t = t * 10 + A
  3. 压位:把新被除数除的结果压入C
  4. 余数:把新的余数放在t
  5. 倒置:压位是从最高位开始的,所以要倒置一下
  6. 前导0:去除C的前导0

除法

// A除以b余t
vector<int> div(vector<int> &A, int b, int &t)
{
// 1初
    vector<int> C;
    t = 0;
    for (int i = A.size() - 1; i >= 0; i -- )
    {
// 2临时被除数
        t = t * 10 + A[i];  // 上一位的余数乘10+A的到新被除数(模仿除法竖式)
// 3压位
        C.push_back(t / b);  // 压入本次被除数的商
// 4余数
        t %= b;  // 得到余数
    }
// 5倒置
    reverse(C.begin(), C.end());  // 压入C是从高到低压的,要倒置
// 6前导0
    while (C.size() > 1 && C.back() == 0) C.pop_back();
    return C;
}
举报

相关推荐

0 条评论