老题新解|大整数减法
《信息学奥赛一本通》第165题:大整数减法
求两个大的正整数相减的差。
输入:共两行,第 1 行是被减数 aaa,第 2 行是减数 bbb(a>ba>ba>b)。每个大整数不超过 200 位,不会有多余的前导 0。
输出:一行,即所求的差。
例如输入:
99999999999999999999999999999999 99999999999输出: 99999999999999999999999900000000
大家好,我是莫小特。
这篇文章给大家带来《信息学奥赛一本通》中的第 165 题:大整数减法。
一、题目描述
求两个大的正整数相减的差。
输入:共两行,第 1 行是被减数 aaa,第 2 行是减数 bbb(a>ba>ba>b)。每个大整数不超过 200 位,不会有多余的前导 0。
输出:一行,即所求的差。
例如输入:
99999999999999999999999999999999 99999999999
输出:99999999999999999999999900000000
二、题意分析
这是一道典型的“大整数运算”题目。由于输入的数字长度可达上百位,C++ 内置整数类型(如 int
, long long
)无法存储,所以要把字符串转换为按位存放的数组来模拟手算减法的过程(从低位到高位逐位相减并处理借位),最后把结果逆序输出并去掉多余的前导零。
常用步骤:
-
读入两个字符串
a
(被减数),b
(减数)。题目已保证a > b
,因此结果非负。 -
将两个字符串从右往左转换成整型数组(或直接按索引访问字符串字符并减去
'0'
),便于做 “低位到高位” 的逐位运算。 -
用一个整型数组
c
存放差的各位,按位相减:c[i] = a[i] - b[i] - borrow
。若不够(负数),则加上 10 并置borrow = 1
,否则borrow = 0
。 -
最后数组
c
的最高位可能为 0,需要去掉前导 0(但结果为 0 时至少保留一位 0)。 -
输出时将
c
从高位到低位顺序打印。
三、完整代码
该题的完整代码如下:
#include <bits/stdc++.h>
using namespace std;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);string a, b;if (!(cin >> a)) return 0;cin >> b;// 将字符串按位从最低位存到数组(下标 0 表示最低位)int lena = a.length();int lenb = b.length();vector<int> A(lena), B(lenb);for (int i = 0; i < lena; ++i) A[i] = a[lena - 1 - i] - '0';for (int i = 0; i < lenb; ++i) B[i] = b[lenb - 1 - i] - '0';// 结果数组,长度至少为 lenavector<int> C(lena, 0);int borrow = 0;for (int i = 0; i < lena; ++i) {int bi = (i < lenb) ? B[i] : 0;int diff = A[i] - bi - borrow;if (diff < 0) {diff += 10;borrow = 1;} else {borrow = 0;}C[i] = diff;}// 删除高位多余的 0(保留至少一位)int pos = lena - 1;while (pos > 0 && C[pos] == 0) --pos;// 输出从高位到低位for (int i = pos; i >= 0; --i) cout << C[i];cout << '\n';return 0;
}
四、代码详解(逐段说明)
-
ios::sync_with_stdio(false); cin.tie(nullptr);
加速输入输出,常用模板。 -
读入字符串
a
、b
:两行输入分别保存被减数和减数。 -
将字符串反向存入整型数组
A
和B
,方便从最低位(下标 0)开始运算:for (int i = 0; i < lena; ++i) A[i] = a[lena - 1 - i] - '0';
这样
A[0]
是个位,A[1]
是十位,依次类推。 -
vector<int> C(lena, 0);
为结果分配空间,长度至少为lena
(被减数的位数)。 -
主循环逐位相减并处理借位:
int diff = A[i] - bi - borrow; if (diff < 0) { diff += 10; borrow = 1; } else borrow = 0; C[i] = diff;
这里
bi
当i >= lenb
时取 0(短数自动补 0)。 -
去掉高位多余的 0:
int pos = lena - 1; while (pos > 0 && C[pos] == 0) --pos;
保证当结果为 0 时依然输出单个
0
。 -
从
pos
到0
逆序输出各位,得到最终结果字符串。
五、复杂度与注意事项
-
时间复杂度 O(L),L 为被减数的位数(<=200),非常快。
-
空间复杂度 O(L)。
-
题目保证
a > b
,所以无需考虑负数结果。但若题目不保证,需要额外比较字符串大小以决定符号输出。 -
注意字符串长度差异,短的数要当作前面补 0 处理。
-
注意去掉前导零,但结果为 0 时应输出单个
0
。
六、总结
这道题是训练字符串与数组模拟“大整数运算”的基础题,考察点包括:
-
字符串与数字的互相转换(
char - '0'
); -
低位到高位的逐位模拟(反向存储或逆序遍历);
-
借位处理逻辑(若差小于 0 则加 10 并借 1);
-
去掉结果的前导零。
常见错误:
-
忘记短数补 0,导致越界或错误结果;
-
去掉所有高位 0(没保留至少一位),当结果为 0 时输出空行;
-
将字符串从前往后直接相减而未处理借位方向(容易出错)。
解题建议:用手算两个长数的减法模拟一次,体会借位传播的规则,然后按位实现;提交前多测试边界:a
与 b
位数相等、b
很短、结果恰好有许多高位 0(需要去掉)以及 a
与 b
相差一位等情况。
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注我哦!
如果有更好的方法也可以在评论区评论哦,我都会看哒~
我们下集见~