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。

谢谢

相关推荐
无损检测小白白26 分钟前
【嵌入式面试题一】
c语言·单片机
CoderYanger1 小时前
A.每日一题:1140. 石子游戏 II
java·程序人生·算法·leetcode·游戏·职场和发展·深度优先
小雨笙笙1 小时前
机器学习:评估模型与选择
人工智能·算法·机器学习
高亦真1 小时前
今天是学习嵌入式的第35天
linux·学习·算法
mengzhi啊1 小时前
QEventLoop loop配合loop.exec();替代while(1)。电脑cpu占用为0,使用while(1)cpu占用率100%
c++·qt
HugoStudio_SWAN1 小时前
洛谷 P1319 / P1320 压缩技术——同一枚硬币的正反面
c++·学习·程序人生·算法
小小晓.2 小时前
C++单例模式万字详解:6种实现演进+线程安全彻底解决+CRTP终极模板
c++·单例模式
j7~3 小时前
【C++11】C++11 新特性全套详解(列表初始化、右值引用、lambda 表达式、function 与 bind 包装器等)
c++·右值引用·lambda表达式·可变参数模板·移动语义·包装器·c++11发展史
wdfk_prog3 小时前
canopennode-rtt推荐,不只可以做从站,也可以承担主站角色
c语言·开发语言·数据库·学习·算法·深度优先
无小道3 小时前
C/C++——可变参数
c语言·开发语言·c++·可变参数