1.大数加法
题目大意
输入两个很大的非负整数(长度超出普通整型、long long 范围),以字符串形式输入,输出相加结果。
核心思路:模拟手工竖式加法,从低位往高位逐位相加,保存进位。
C++ 完整代码
cpp
运行
cpp
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string a, b;
cin >> a >> b;
// 反转字符串,方便从低位开始运算
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
string res;
int carry = 0; // 进位
int i = 0;
// 只要还有数字或者还有进位就继续循环
while (i < a.size() || i < b.size() || carry)
{
int sum = carry;
if (i < a.size()) sum += a[i] - '0';
if (i < b.size()) sum += b[i] - '0';
carry = sum / 10;
res.push_back(sum % 10 + '0');
i++;
}
// 反转回来得到正确顺序
reverse(res.begin(), res.end());
cout << res << endl;
return 0;
}
思路详解
- 反转字符串 数字字符串
123反转成321,下标 0 对应个位,方便统一处理低位。 - 逐位求和 取出两个数当前位置数字 + 进位;
sum % 10→ 当前位结果;sum / 10→ 更新进位。 - 循环终止条件 两个字符串遍历完 并且进位为 0,防止最高位产生新进位被漏掉(如 999 + 1)。
- 最后反转结果输出
测试样例
输入:
plaintext
999
1
输出:
plaintext
1000
输入:
plaintext
123456789
987654321
输出:
plaintext
1111111110
2.链表相加(二)
题目描述
给定两个链表,链表每个节点代表数字一位,高位在前 。 例如: 9->3->7 代表 937 6->3 代表 63 相加:937 + 63 = 1000 输出链表:1->0->0->0
区别于普通链表相加(低位在前),本题高位在前,无法直接从表头遍历相加。
思路
方案:反转链表 → 低位在前正常相加 → 反转结果链表
- 反转 l1、l2,变成低位在前
- 逐位相加,处理进位,生成新链表
- 反转结果链表,恢复高位在前输出
C++ 完整 AC 代码
cpp
运行
cpp
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
// 反转链表
ListNode* reverseList(ListNode* head) {
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur) {
ListNode* nxt = cur->next;
cur->next = pre;
pre = cur;
cur = nxt;
}
return pre;
}
class Solution {
public:
ListNode* addInList(ListNode* head1, ListNode* head2) {
ListNode* l1 = reverseList(head1);
ListNode* l2 = reverseList(head2);
ListNode dummy(0);
ListNode* cur = &dummy;
int carry = 0;
while(l1 || l2 || carry) {
int sum = carry;
if(l1) {
sum += l1->val;
l1 = l1->next;
}
if(l2) {
sum += l2->val;
l2 = l2->next;
}
carry = sum / 10;
cur->next = new ListNode(sum % 10);
cur = cur->next;
}
// 结果现在低位在前,反转回来
return reverseList(dummy.next);
}
};
另一种不反转链表方案(栈)
原理:利用栈后进先出,把节点压栈,依次取出低位相加,最后头插法构建结果链表
cpp
运行
cpp
#include <stack>
ListNode* addInList(ListNode* head1, ListNode* head2) {
stack<int> st1, st2;
while(head1) {
st1.push(head1->val);
head1 = head1->next;
}
while(head2) {
st2.push(head2->val);
head2 = head2->next;
}
ListNode* res = nullptr;
int carry = 0;
while(!st1.empty() || !st2.empty() || carry) {
int sum = carry;
if(!st1.empty()) {
sum += st1.top(); st1.pop();
}
if(!st2.empty()) {
sum += st2.top(); st2.pop();
}
carry = sum / 10;
// 头插
ListNode* node = new ListNode(sum % 10);
node->next = res;
res = node;
}
return res;
}
两种方案对比
- 反转链表 空间复杂度 O (1)(只新建结果节点),推荐面试手写。
- 栈 空间 O (n+m),代码直观,不需要写反转函数。
易错点
- 不要忘记循环条件
carry,最高位进位(999+1) - 结果链表最后一定要反转!
- 头插法构建链表时注意指针顺序
3.大数乘法
原理
普通 int/long long 存不下超大数字,用字符串存储。 模拟竖式乘法: num1[i] × num2[j] 的结果,落在乘积数组 i+j 和 i+j+1 位置。
规律核心:
plaintext
cpp
num1 下标 i(从右往左)
num2 下标 j(从右往左)
乘积低位:pos = i+j+1
乘积高位:pos = i+j
C++ AC 代码
cpp
运行
cpp
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
string multiply(string num1, string num2) {
// 处理0特判
if (num1 == "0" || num2 == "0")
return "0";
int n = num1.size(), m = num2.size();
// 两数相乘最多 n+m 位
vector<int> res(n + m, 0);
// 逆序遍历
for (int i = n - 1; i >= 0; --i) {
int a = num1[i] - '0';
for (int j = m - 1; j >= 0; --j) {
int b = num2[j] - '0';
int mul = a * b;
// 对应位置
int p1 = i + j;
int p2 = i + j + 1;
int sum = mul + res[p2];
res[p2] = sum % 10;
res[p1] += sum / 10;
}
}
// 转字符串,跳过前导0
string ans;
for (int x : res) {
if (!(ans.empty() && x == 0)) {
ans.push_back(x + '0');
}
}
return ans;
}
int main() {
string a, b;
cin >> a >> b;
cout << multiply(a, b) << endl;
return 0;
}
执行示例
输入:
plaintext
999
999
输出:
plaintext
998001
输入:
plaintext
123456789
987654321
输出:
plaintext
121932631112635269
关键点梳理
- 最大长度 长度 n × m 的两个数,乘积最多
n+m位,数组开n+m。 - 位置映射
num1[i] * num2[j]→res[i+j]、res[i+j+1] - 先累加再取进位 不要直接赋值,要加上该位置原有数值!
plaintext
int sum = a*b + res[p2];
res[p2] = sum %10;
res[p1] += sum /10;
- 前导 0 清除 数组开头可能存在 0,拼接字符串时跳过。
- 边界特判 任意一个数字为
"0",直接返回"0",否则会出现空串或者多个前导 0。
谢谢