题解:洛谷 P2142 高精度减法

【题目来源】

洛谷:P2142 高精度减法 - 洛谷

【题目描述】

高精度减法。

【输入】

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

【输出】

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

【输入样例】

2
1

【输出样例】

1

【核心思想】

  1. 问题分析:给定两个可能非常大的整数 \(a\)\(b\)(长度可达 \(10^5\) 位),需要计算它们的差 \(a - b\)。由于整数大小远超标准数据类型范围,必须使用高精度算法模拟手算减法过程:从最低位开始逐位相减,若被减数当前位小于减数当前位,则向高位借位。同时需判断结果符号,若 \(a < b\) 则输出负号。

  2. 算法选择

    • 字符串转逆序数组:将两个整数以字符串形式读入,按位逆序存入整型数组(或 vector),使个位对齐在索引 0 处,便于从低位向高位计算。
    • 大小比较:先比较两数绝对值大小,若 \(a < b\) 则交换 \(a\)\(b\) 并标记负号,保证计算时始终用大数减小数。
    • 逐位减法 + 借位:遍历每一位,被减数当前位减去减数当前位及上次借位,若结果为负则加 10 并标记借位 1,否则借位为 0。
    • 去除前导零:结果数组高位可能有多余的 0,需删除(但至少保留一位,避免输出空串)。
  3. 关键步骤(以 vector 实现为例):

    • 读入与预处理:读取字符串 \(a\)\(b\),逆序存入 vector<int> A, B,其中 A[0] 为个位。
    • 比较大小:若 A.size() != B.size(),长度长的大;长度相同则从高位向低位比较。
    • 交换与符号标记:若 A < B,则交换 AB,并标记负号。
    • 逐位减法:循环 i 从 0 到 A.size()-1
      • t = A[i] - 借位(借位初始为 0)。
      • i < B.size(),则 t -= B[i]
      • t < 0,则 t += 10,借位设为 1;否则借位设为 0。
      • t 存入结果数组 C
    • 去除前导零:移除 C 末尾多余的 0,但若 C 为空则保留一个 0。
    • 输出:若有负号先输出 -,再逆序输出 C
  4. 时间/空间复杂度

    • 时间复杂度:\(O(\max(|a|, |b|))\),逐位遍历一次。
    • 空间复杂度:\(O(\max(|a|, |b|))\),存储三个数组。
  5. 高精度模拟的核心思想

    • 逆序存储:将数字字符串反转后存入数组,使最低位对齐,方便从低位开始逐位计算。
    • 借位处理:模拟手算减法中的“借位”操作,通过 t < 0 判断是否需要借位,并更新借位标志。
    • 符号判断:先比较绝对值大小,若被减数较小则交换并输出负号,避免处理负数减法(\(a-b = -(b-a)\))。
    • 前导零去除:高位多余的零不影响数值,需在输出前清理,但保留至少一位数字。
    • 适用于所有大整数加减法、乘法等运算,是算法竞赛中处理超大整数的标准方法。

【算法标签】

普及- #高精度

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;  // 定义数组的最大长度
int A[N], B[N], C[N];  // A和B用于存储输入的两个大数,C用于存储结果
int la, lb, lc;        // la, lb分别表示A和B的长度,lc表示结果C的长度
string a, b;           // 用于存储输入的两个大数的字符串形式

// 比较函数,用于比较两个大数的大小
bool cmp(int A[], int B[])
{
    if (la != lb) return la > lb;  // 如果长度不同,直接比较长度
    for (int i = la - 1; i >= 0; i--)  // 从最高位开始逐位比较
        if (A[i] != B[i])
            return A[i] > B[i];  // 如果某一位不同,返回比较结果
    return true;  // 如果所有位都相同,返回true,避免结果为-0
}

// 大数减法函数,计算A - B,结果存储在C中
void sub(int A[], int B[], int C[])
{
    for (int i = 0; i < lc; i++) {
        if (A[i] < B[i]) {
            A[i + 1]--;  // 借位
            A[i] += 10;  // 当前位加10
        }
        C[i] = A[i] - B[i];  // 计算当前位的差值并存储在C中
    }
    while (lc && C[lc] == 0) lc--;  // 去掉结果中的前导0
}

int main()
{
    cin >> a >> b;  // 输入两个大数
    la = a.size(), lb = b.size(), lc = max(la, lb);  // 计算长度

    // 将字符串形式的大数转换为数组形式,并逆序存储(方便计算)
    for (int i = la - 1; i >= 0; i--)
        A[la - 1 - i] = a[i] - '0';
    for (int i = lb - 1; i >= 0; i--)
        B[lb - 1 - i] = b[i] - '0';

    // 如果A小于B,交换A和B,并输出负号
    if (!cmp(A, B)) {
        swap(A, B);
        cout << '-';
    }

    // 执行减法操作
    sub(A, B, C);

    // 输出结果
    for (int i = lc; i >= 0; i--)
        cout << C[i];

    return 0;
}
#include <bits/stdc++.h>
using namespace std;

string a, b;          // 用于存储输入的两个大数的字符串形式
vector<int> A, B;     // 使用vector存储大数的每一位,方便动态调整大小

// 比较函数,用于比较两个大数的大小
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
}

// 大数减法函数,计算 A - B,结果存储在 C 中
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;  // 用于存储结果
    for (int i = 0, t = 0; i < A.size(); i++)  // t 表示借位
    {
        t = A[i] - t;  // 先减去借位
        if (i < B.size()) t -= B[i];  // 如果 B 还有位数,减去 B 的当前位
        C.push_back((t + 10) % 10);  // 将当前位的差值存入 C(处理负数情况)
        if (t < 0) t = 1;  // 如果差值为负,需要借位
        else t = 0;        // 否则不需要借位
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back();  // 去掉结果中的前导0
    return C;
}

int main()
{
    cin >> a >> b;  // 输入两个大数

    // 将字符串形式的大数转换为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');

    // 比较 A 和 B 的大小
    if (cmp(A, B))  // 如果 A >= B
    {
        auto C = sub(A, B);  // 计算 A - B
        for (int i = C.size() - 1; i >= 0; i--) cout << C[i];  // 输出结果
    }
    else  // 如果 A < B
    {
        auto C = sub(B, A);  // 计算 B - A
        cout << "-";         // 输出负号
        for (int i = C.size() - 1; i >= 0; i--) cout << C[i];  // 输出结果
    }
    return 0;
}

【运行结果】

2
1
1
posted @ 2026-09-02 21:40  团爸讲算法  阅读(15)  评论(0)    收藏  举报