C/C++每日一练6

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;
}

思路详解

  1. 反转字符串 数字字符串 123 反转成 321,下标 0 对应个位,方便统一处理低位。
  2. 逐位求和 取出两个数当前位置数字 + 进位; sum % 10 → 当前位结果; sum / 10 → 更新进位。
  3. 循环终止条件 两个字符串遍历完 并且进位为 0,防止最高位产生新进位被漏掉(如 999 + 1)。
  4. 最后反转结果输出

测试样例

输入:

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

区别于普通链表相加(低位在前),本题高位在前,无法直接从表头遍历相加。

思路

方案:反转链表 → 低位在前正常相加 → 反转结果链表

  1. 反转 l1、l2,变成低位在前
  2. 逐位相加,处理进位,生成新链表
  3. 反转结果链表,恢复高位在前输出

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;
}

两种方案对比

  1. 反转链表 空间复杂度 O (1)(只新建结果节点),推荐面试手写。
  2. 空间 O (n+m),代码直观,不需要写反转函数。

易错点

  1. 不要忘记循环条件 carry,最高位进位(999+1)
  2. 结果链表最后一定要反转!
  3. 头插法构建链表时注意指针顺序

3.大数乘法

原理

普通 int/long long 存不下超大数字,用字符串存储。 模拟竖式乘法: num1[i] × num2[j] 的结果,落在乘积数组 i+ji+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

关键点梳理

  1. 最大长度 长度 n × m 的两个数,乘积最多 n+m 位,数组开 n+m
  2. 位置映射 num1[i] * num2[j]res[i+j]res[i+j+1]
  3. 先累加再取进位 不要直接赋值,要加上该位置原有数值!

plaintext

复制代码
int sum = a*b + res[p2];
res[p2] = sum %10;
res[p1] += sum /10;
  1. 前导 0 清除 数组开头可能存在 0,拼接字符串时跳过。
  2. 边界特判 任意一个数字为 "0",直接返回 "0",否则会出现空串或者多个前导 0。

谢谢

相关推荐
wdfk_prog1 小时前
嵌入式面试真题第 13 题:单硬件 Timer 下的高精度多路软件定时器架构设计
c语言·开发语言·面试·职场和发展·嵌入式
念恒123062 小时前
网络基础
linux·网络·c++
AI小码2 小时前
把动作「画」给视频世界模型,跨本体双向推演,李飞飞参与
大数据·人工智能·算法·ai·大模型·音视频·编程
mct1232 小时前
c++ iconv 字符utf-8转换gb2312失败
开发语言·c++
ziguo11222 小时前
Windows API 文件操作超级指南——从入门到内核
c++·windows·visualstudio
时间的拾荒人2 小时前
MySQL C语言连接 - 从入门到实战
android·c语言·mysql
KaMeidebaby3 小时前
卡梅德生物技术快报|bli亲和力检测gst:告别批量跑胶:BLI实时酶切监测技术加速GST融合蛋白下游流程优化
前端·网络·数据库·人工智能·算法
alphaTao3 小时前
LeetCode 每日一题 2026/7/20-2026/7/26
算法·leetcode
zhangfeng11334 小时前
Ascendc 大语言模型框架 AscendCraft 和pypto 的区别 pypto生成算子c++源码吗
c++·人工智能·语言模型·算子开发