题解 P1553 【数字反转(升级版)】

· · 题解

如果你对 STL 了解得比较透彻,那么这篇题解一定是最简单的(虽然有点长,但思路很清晰)。如果你不是很懂 STL,借此机会了解、学习一下也无妨。 主要思路是,读如字符串后,判断字符串中是属于哪一种类型的数字。一共有四种情况:正整数、正实数、正分数、正百分数。

综上,我们有以下几个问题需要解决:

  1. 如何反转?用 STL 中的 std::reverse()
  2. 如何去掉前导零?先遍历一遍字符串,看看有多少前导零,然后 std::string::erase() 即可。
  3. 如何提取出子字符串?std::string::substr()

对于以上三个函数不是很懂?没关系,文末会有具体解释。 还有两点需要注意,分别是:

  1. 但要注意,如果数字本身就是零,按照上面的做法会得到空串。所以需要特判。
  2. 还要注意,小数点之后的部分还需要去掉“后导零”。

代码如下:

//【P1553】数字反转(升级版) - 洛谷 - 100
#include <string>
#include <iostream>
#include <algorithm>

// 自己写的反转函数,返回反转并去掉前导零之后的字符串
std::string reverse(std::string s) {
    int zeroCount = 0;
    std::reverse(s.begin(), s.end()); // 反转
    // 范围 for 循环,用于统计前导零个数
    for (auto i : s)
        if (i == 48) ++zeroCount;
        else break;
    s.erase(s.begin(), s.begin() + zeroCount);
    return (s != "" ? s : "0"); // 特判
}

// 用于去掉后导零
std::string deleteTail(std::string s) { 
    int zeroCount = 0;
    for (int i = s.size() - 1; i >= 0; --i)
        if (s[i] == 48) ++zeroCount;
        else break;
    s.erase(s.end() - zeroCount, s.end());
    return (s != "" ? s : "0");
}

int main() {
    std::string s;
    std::cin >> s;
    if (s.back() == '%') {
        std::cout << reverse(s.substr(0, s.size() - 1)) << "%" << std::endl;
        return 0;
    }
    for (auto i : s) {
        std::string left, right;
        // 其实还有一种不需要遍历字符串的做法,直接 find() 即可,但是当时没想到
        if (i == '/') {
            left = s.substr(0, s.find("/"));
            right = s.substr(s.find("/") + 1);
            std::cout << reverse(left) << "/" << reverse(right) << std::endl;
            return 0;
        }
        if (i == '.') {
            left = s.substr(0, s.find("."));
            right = s.substr(s.find(".") + 1);
            std::cout << reverse(left) << "." << deleteTail(reverse(right)) << std::endl;
            return 0;
        }
    }
    // 最后剩下的一种情况是正整数
    std::cout << reverse(s) << std::endl;
    return 0;
}

分别解释一下用到的 STL 算法。

  1. std::reverse(),顾名思义,用于反转序列。需要提供首尾迭代器作为参数。
  2. std::string::erase(),传入两个迭代器 l,r,清除[l,r)范围内的字符。
  3. std::string::substr(),用于提取子字符串,用法与前者类似。
  4. std::string::find(),用来查找字串在母串中第一次出现的位置。

如果还是不太懂,不要着急,初学 STL 总要花费些时间的。与快排等算法结合学习,会起到事半功倍的效果。另外,cppreference.com 这个网站非常有用。如果有不理解的,可以随时去查。