A+B problem - 题解
标签与难度
标签: 数学, 模拟, 字符串处理, 入门, 整数反转 难度: 800
题目大意喵~
你好呀,未来的算法大师!本喵今天带来了一道看起来像 A+B,但又有点不一样的小趣题,喵~
题目是这样定义的:
- 首先,有一个叫**“反转数”**的概念。就是把一个用阿拉伯数字写的数,把它的数字顺序完全颠倒过来。比如
1234的反转数就是4321。特别注意哦,反转后如果前面有0,是要去掉的,比如1000的反转数就是1。 - 我们用
Rev(x)来表示对数字x进行反转操作。 - 题目会给你两个正整数
a和b,你需要计算一个**“反转和”**,它的公式是:Rev(Rev(a) + Rev(b))。
举个栗子来帮助理解吧! 如果输入的 a 是 123,b 是 100:
- 先把
a反转:Rev(123)得到321。 - 再把
b反转:Rev(100)得到1。 - 然后把这两个反转后的数加起来:
321 + 1 = 322。 - 最后,把这个和再反转一次:
Rev(322)得到223。 所以,223就是我们要输出的最终答案啦,喵~
解题思路分析
看到这个题目,我们的猫爪爪是不是有点痒痒了呀?别急,我们一步一步来分析,喵~
这个问题的核心,其实就是一个叫做“数字反转”的小魔法。只要我们能实现一个函数,可以完美地把任何一个数字颠倒过来,那整个问题就迎刃而解啦!
那么,要怎么实现这个 Rev(x) 魔法呢?本喵这里有一个非常经典的数字戏法哦!
我们以 123 为例,看看怎么把它变成 321:
- 首先,我们需要一个地方来存放我们反转后的新数字,叫它
reversed_num吧,一开始它是0。 - 我们用一个循环,只要原来的数字
num还不是0,就一直进行操作。 - 第一步:取个位数 怎么拿到
123的最后一位3呢?用取模运算就可以啦!123 % 10的结果就是3。 - 第二步:把个位数“拼接”到新数字上 现在我们拿到了
3,怎么把它放到reversed_num里呢? 我们可以先把reversed_num乘以10(这样就给新来的数字腾出了一个位置),然后再把3加上去。reversed_num = reversed_num * 10 + 3=>0 * 10 + 3 = 3。 - 第三步:去掉已经用过的个位数
123里的3已经被我们拿走了,怎么让它变成12呢?用整除运算!123 / 10的结果就是12。
现在,num 变成了 12,reversed_num 变成了 3。我们继续循环:
- 取
12的个位数2(12 % 10)。 - 把它拼接到
reversed_num上:reversed_num = 3 * 10 + 2 = 32。 - 去掉
12的个位数:num = 12 / 10 = 1。
继续,num 是 1,reversed_num 是 32:
- 取
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)) 一步步计算就好啦:
- 定义一个
reverseInteger函数来实现上面的魔法。 - 在主函数里,读入
a和b。 - 调用
reverseInteger(a)得到rev_a。 - 调用
reverseInteger(b)得到rev_b。 - 计算它们的和
sum_of_revs = rev_a + rev_b。 - 最后再调用一次
reverseInteger(sum_of_revs),把结果打印出来就完成任务啦!
代码实现
这是本喵根据上面的思路,精心为你准备的一份代码,注释超详细的哦,希望能帮到你,喵~
#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;
}复杂度分析
时间复杂度: 我们对每个数字 a 和 b 做的反转操作,循环的次数只和数字的位数有关,对吧?一个数字 的位数大约是 。整个过程需要对 a、b 以及它们的和各反转一次,所以总的时间复杂度和输入数字的位数成正比。这是一个非常快的算法,的说!
空间复杂度: 在我们的实现中,
reverseInteger函数只使用了几个固定的变量(如reversed_num,digit)来存储中间结果,没有使用任何随输入大小变化的额外数据结构(比如数组)。所以空间复杂度是 ,非常节省内存呢,喵~
知识点总结
通过这道可爱的小题,我们学会了几个有用的知识点呐:
- 整数反转算法: 这是最核心的收获!通过
num % 10取个位数和num / 10去掉个位数,配合res = res * 10 + digit的累加方式,是处理数字各位的经典技巧。 - 问题分解: 面对一个看起来有点绕的公式
Rev(Rev(a) + Rev(b)),我们没有慌张,而是把它分解成“实现Rev函数”和“按顺序调用”两个独立的、更简单的子问题。这是解决复杂问题的重要思想! - 数据类型选择: 考虑到数字反转后可能会变大(例如
1000000009反转后是9000000001),或者两个反转数相加后可能会很大,主动选择long long是一个好习惯,可以避免潜在的整数溢出问题。 - 模块化编程: 把核心功能(数字反转)封装成一个独立的函数
reverseInteger,让主函数main的逻辑变得非常清晰易读。
希望本喵的讲解对你有帮助!继续加油,你超棒的,喵~!