Skip to content

A+B problem - 题解

标签与难度

标签: 数学, 模拟, 字符串处理, 入门, 整数反转 难度: 800

题目大意喵~

你好呀,未来的算法大师!本喵今天带来了一道看起来像 A+B,但又有点不一样的小趣题,喵~

题目是这样定义的:

  1. 首先,有一个叫**“反转数”**的概念。就是把一个用阿拉伯数字写的数,把它的数字顺序完全颠倒过来。比如 1234 的反转数就是 4321。特别注意哦,反转后如果前面有 0,是要去掉的,比如 1000 的反转数就是 1
  2. 我们用 Rev(x) 来表示对数字 x 进行反转操作。
  3. 题目会给你两个正整数 ab,你需要计算一个**“反转和”**,它的公式是:Rev(Rev(a) + Rev(b))

举个栗子来帮助理解吧! 如果输入的 a123b100

  1. 先把 a 反转:Rev(123) 得到 321
  2. 再把 b 反转:Rev(100) 得到 1
  3. 然后把这两个反转后的数加起来:321 + 1 = 322
  4. 最后,把这个和再反转一次:Rev(322) 得到 223。 所以,223 就是我们要输出的最终答案啦,喵~

解题思路分析

看到这个题目,我们的猫爪爪是不是有点痒痒了呀?别急,我们一步一步来分析,喵~

这个问题的核心,其实就是一个叫做“数字反转”的小魔法。只要我们能实现一个函数,可以完美地把任何一个数字颠倒过来,那整个问题就迎刃而解啦!

那么,要怎么实现这个 Rev(x) 魔法呢?本喵这里有一个非常经典的数字戏法哦!

我们以 123 为例,看看怎么把它变成 321

  1. 首先,我们需要一个地方来存放我们反转后的新数字,叫它 reversed_num 吧,一开始它是 0
  2. 我们用一个循环,只要原来的数字 num 还不是 0,就一直进行操作。
  3. 第一步:取个位数 怎么拿到 123 的最后一位 3 呢?用取模运算就可以啦!123 % 10 的结果就是 3
  4. 第二步:把个位数“拼接”到新数字上 现在我们拿到了 3,怎么把它放到 reversed_num 里呢? 我们可以先把 reversed_num 乘以 10(这样就给新来的数字腾出了一个位置),然后再把 3 加上去。 reversed_num = reversed_num * 10 + 3 => 0 * 10 + 3 = 3
  5. 第三步:去掉已经用过的个位数123 里的 3 已经被我们拿走了,怎么让它变成 12 呢?用整除运算!123 / 10 的结果就是 12

现在,num 变成了 12reversed_num 变成了 3。我们继续循环:

  • 12 的个位数 2 (12 % 10)。
  • 把它拼接到 reversed_num 上:reversed_num = 3 * 10 + 2 = 32
  • 去掉 12 的个位数:num = 12 / 10 = 1

继续,num1reversed_num32

  • 1 的个位数 1 (1 % 10)。
  • 把它拼接到 reversed_num 上:reversed_num = 32 * 10 + 1 = 321
  • 去掉 1 的个位数:num = 1 / 10 = 0

现在 num 变成 0 了,循环结束!我们得到的 reversed_num 正好就是 321,大功告成,喵~

这个方法还有一个很棒的优点哦!对于像 1000 这样的数字,它会依次取出 0, 0, 0, 1。因为 reversed_num 一开始是 0,所以前面的 0 加进去都不会改变它的值,直到 1 进来,结果就变成了 1。这完美地处理了题目中“去掉前导零”的要求,是不是很聪明呀!

有了这个“数字反转”魔法,剩下的就简单啦!我们只需要按照公式 Rev(Rev(a) + Rev(b)) 一步步计算就好啦:

  1. 定义一个 reverseInteger 函数来实现上面的魔法。
  2. 在主函数里,读入 ab
  3. 调用 reverseInteger(a) 得到 rev_a
  4. 调用 reverseInteger(b) 得到 rev_b
  5. 计算它们的和 sum_of_revs = rev_a + rev_b
  6. 最后再调用一次 reverseInteger(sum_of_revs),把结果打印出来就完成任务啦!

代码实现

这是本喵根据上面的思路,精心为你准备的一份代码,注释超详细的哦,希望能帮到你,喵~

cpp
#include <iostream>

// 为了防止数字反转或相加后超出普通 int 的范围,我们使用 long long,这样更安全喵~
using ll = long long;

/**
 * @brief 实现数字反转的魔法函数
 * @param num 需要被反转的原始数字
 * @return 反转后的数字
 * 
 * 例子:
 *  - 输入 123, 返回 321
 *  - 输入 100, 返回 1
 */
ll reverseInteger(ll num) {
    ll reversed_num = 0; // 用于存放反转结果的变量,初始化为0

    // 当原始数字不为0时,循环执行
    while (num > 0) {
        // 1. 取出 num 的最后一位数字
        int digit = num % 10;

        // 2. 将这个数字“追加”到 reversed_num 的末尾
        //    - reversed_num * 10 是为了给新数字腾出个位
        //    - + digit 就是把新数字放进去
        reversed_num = reversed_num * 10 + digit;

        // 3. 从 num 中移除已经处理过的最后一位
        num /= 10;
    }

    return reversed_num;
}

int main() {
    // 为了让输入输出更快,本喵施展了加速魔法!
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int t; // 测试用例的数量
    std::cin >> t;
    while (t--) {
        ll a, b; // 读入两个正整数
        std::cin >> a >> b;

        // 步骤 1: 反转 a 和 b
        ll rev_a = reverseInteger(a);
        ll rev_b = reverseInteger(b);

        // 步骤 2: 计算反转后的和
        ll sum_of_revs = rev_a + rev_b;

        // 步骤 3: 再次反转这个和
        ll final_result = reverseInteger(sum_of_revs);

        // 输出最终答案,喵~
        std::cout << final_result << std::endl;
    }

    return 0;
}

复杂度分析

  • 时间复杂度: O(log10a+log10b)O(\log_{10} a + \log_{10} b) 我们对每个数字 a 和 b 做的反转操作,循环的次数只和数字的位数有关,对吧?一个数字 NN 的位数大约是 log10N\log_{10} N。整个过程需要对 a、b 以及它们的和各反转一次,所以总的时间复杂度和输入数字的位数成正比。这是一个非常快的算法,的说!

  • 空间复杂度: O(1)O(1) 在我们的实现中,reverseInteger 函数只使用了几个固定的变量(如 reversed_num, digit)来存储中间结果,没有使用任何随输入大小变化的额外数据结构(比如数组)。所以空间复杂度是 O(1)O(1),非常节省内存呢,喵~

知识点总结

通过这道可爱的小题,我们学会了几个有用的知识点呐:

  1. 整数反转算法: 这是最核心的收获!通过 num % 10 取个位数和 num / 10 去掉个位数,配合 res = res * 10 + digit 的累加方式,是处理数字各位的经典技巧。
  2. 问题分解: 面对一个看起来有点绕的公式 Rev(Rev(a) + Rev(b)),我们没有慌张,而是把它分解成“实现Rev函数”和“按顺序调用”两个独立的、更简单的子问题。这是解决复杂问题的重要思想!
  3. 数据类型选择: 考虑到数字反转后可能会变大(例如 1000000009 反转后是 9000000001),或者两个反转数相加后可能会很大,主动选择 long long 是一个好习惯,可以避免潜在的整数溢出问题。
  4. 模块化编程: 把核心功能(数字反转)封装成一个独立的函数 reverseInteger,让主函数 main 的逻辑变得非常清晰易读。

希望本喵的讲解对你有帮助!继续加油,你超棒的,喵~!