不能直接用 int 或 long long 是因为其位宽有限:int 通常仅支持约 10 位十进制数,long long 约 19 位,而百位数相乘结果可达 200 位,必然溢出;必须用数组或 vector 逆序存储各位数字,模拟竖式乘法——逐位相乘、累加到对应位置(i+j)、统一进位、去除前导零。

为什么不能直接用 int 或 long long 做大整数乘法
因为标准整型有位宽限制:int 通常最多表示 10 位十进制数,long long 也只撑到约 19 位。一旦两个百位数相乘,结果可能超 200 位——早溢出了。这时候必须把数字拆成单个数字存进数组,手动模拟竖式乘法。
核心思路是:用 vector<int></int>(或普通 int[])从低位到高位存每一位数字,比如 "123" 存为 {3, 2, 1},方便进位处理。
如何用数组模拟竖式乘法(手算逻辑转代码)
关键不是“写个函数就行”,而是对齐、逐位相乘、累加、进位这四步不能错顺序。常见错误是进位没在每轮乘完就处理,导致高位叠加混乱。
- 先将两个字符串转为逆序数组(低位在前),如
"99" → {9,9},"9" → {9} - 结果数组长度至少为
len1 + len2(因为 n 位 × m 位 最多 n+m 位) - 双层循环:外层遍历被乘数每位
i,内层遍历乘数每位j,把res[i+j] += a[i] * b[j] - **必须单独做一轮进位**:从
0到len1+len2-1扫一遍,res[k+1] += res[k] / 10; res[k] %= 10
示例片段(不带输入校验):
立即学习“C++免费学习笔记(深入)”;
vector<int> multiply(const string& num1, const string& num2) {
if (num1 == "0" || num2 == "0") return {0};
vector<int> a, b, res(num1.size() + num2.size(), 0);
for (int i = num1.size()-1; i >= 0; i--) a.push_back(num1[i]-'0');
for (int i = num2.size()-1; i >= 0; i--) b.push_back(num2[i]-'0');
for (int i = 0; i < a.size(); i++)
for (int j = 0; j < b.size(); j++)
res[i+j] += a[i] * b[j];
for (int i = 0; i < res.size(); i++) {
if (res[i] >= 10) {
res[i+1] += res[i] / 10;
res[i] %= 10;
}
}
while (res.size() > 1 && res.back() == 0) res.pop_back();
reverse(res.begin(), res.end());
return res;
}
vector<int></int> 和 int[] 选哪个?内存与边界怎么控
用 vector 更安全,但要注意它默认初始化为 0,省去手动清零;而裸 int arr[1000] 必须 memset(arr, 0, sizeof(arr)),否则残留值会污染结果。
长度预估不能太小:两个 1000 位数相乘,结果最多 2000 位,但进位可能让索引跑到 i+j+1,所以开 2005 比较稳妥。常见坑是结果数组越界写入,尤其在没检查 res.size() 就访问 res[i+1] 时。
- 字符串转数组时跳过前导空格和符号(如有负号需额外处理)
- 乘积为 0 时要特判,否则逆序后只剩一个 0 却被
pop_back()干掉 - 输出时记得把高位的 0 过滤掉(除了全 0 情况),否则打印出
"000123"
性能瓶颈在哪?什么时候该换其他方法
O(n²) 时间复杂度在万位数以内还能接受,但超过 10⁴ 位后会明显变慢。这不是算法缺陷,而是竖式本质决定的——每个数位都要和其他所有位乘一次。
如果真要处理超长整数(比如密码学场景),别硬写数组模拟:直接用 boost::multiprecision::cpp_int,或者调用 GMP 库。自己实现只适合理解原理、应付 OJ 题或教学场景。
最容易被忽略的一点:输入字符串可能含非法字符,而多数教程样例都假设只有数字。实际使用前务必加 isdigit() 校验,否则 'a'-'0' 会得到负值,后续进位全乱。


















