洛谷:P1553:数字反转(升级版)


洛谷:P1553:数字反转(升级版)

题目

P1553:数字反转(升级版)

分析

如果熟悉C++中字符串(string)的各个操作函数,这道题目可以很直观地解决。

我们先看各种输入类型都可能会用到的去前导0和后导0(仅小数部分)的处理。

去前导0

如果一个数字反转后变成000123,我们只要输出123即可。这里的洞见是:找到第一个不是0的位置。string有一个成员函数可以处理这个任务:

string removeLeadingZeros(string s)
{
    int pos = s.find_first_not_of("0");
    if (pos == string::npos)
    {
        return "0";
    }
    return s.substr(pos);
}

我们用find_first_not_of找到第一个不是0的位置,然后取得从这个位置开始余下的所有字符。同时,我们考虑了极端情况:如果一串字符都是0怎么办?这时,按照题意应该是简单地返回"0"

去后导0

根据题意,去后导0只会在小数部分出现。比如(.)1230,我们只要输出(.)123即可。这里的洞见是:找到最后一个不是0的位置。string有一个成员函数可以处理:

string removeTrailingZeros(string s)
{
    int pos = s.find_last_not_of("0");
    if (pos == string::npos)
    {
        return "0";
    }
    return s.substr(0, pos + 1);
}

我们用find_last_not_of找到最后一个不是0的位置,然后得到这个位置之前的所有字符。同时,也要考虑极端情况。

注意,这里涉及了string.substr(start, end)的用法,需要说明。start/end确定了子字符串的起始位置,但它是个左闭右开(\([start, end)\))的区间。在后续的输入处理中,我们还会用到substr

根据输入进行处理

根据题意,输入的“数字”(字符串)有四种类型:整数、小数、分数、百分数。针对这四种输入格式,需要不同的处理方式。

小数处理

基本流程是:

flowchart TD A["找到小数点位置pos"] --> B["分割数字,得到整数部分、小数部分"] --> C["整数部分反转,去前导0"] --> D["小数部分反转,去后导0"] --> E["输出"]

字符串反转我们可以用reverse(s.begin(), s.end())完成。代码为:

if (s.find(".") != string::npos)
{
    int pos = s.find(".");
    string whole = s.substr(0, pos);
    string decimal = s.substr(pos + 1, s.size());
    reverse(whole.begin(), whole.end());
    reverse(decimal.begin(), decimal.end());
    whole = removeLeadingZeros(whole);
    decimal = removeTrailingZeros(decimal);
    cout << whole << "." << decimal << endl;
}

分数和百分数处理

与“小数处理类似”,但只需要去前导0

整数处理

整数处理只需要反转和去前导0即可。

答案

思考

string类中有很多有用的方法,值得花点时间去研究一下。

Previous Next