刷到的进来刷题了!!!【数字反转升级版c++】

这道题考了很多字符串的操作,大家可以练习一下,检测自己字符串操作是否熟练

P1553 数字反转(升级版)【出自洛谷】

 字符串操作不熟悉的可以参考我的这篇文章,或许对你会有帮助:)

c++头文件及常见函数大全

题目背景

以下为原题面,仅供参考:

给定一个数,请将该数各个位上数字反转得到一个新数。

这次与 NOIP 2011 普及组第一题不同的是:这个数可以是小数,分数,百分数,整数。整数反转是将所有数位对调;小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分;分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母;百分数的分子一定是整数,百分数只改变数字部分。整数新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零;小数新数的末尾不为 0(除非小数部分除了 0 没有别的数,那么只保留1个 0);分数不约分,分子和分母都不是小数(约分滴童鞋抱歉了,不能过哦。输入数据保证分母不为 0),本次没有负数。

题目描述

给定一个数,请将该数各个位上数字反转得到一个新数。

这次与 NOIp2011 普及组第一题不同的是:这个数可以是小数,分数,百分数,整数。

  • 整数反转是将所有数位对调。

  • 小数反转是把整数部分的数反转,再将小数部分的数反转,不交换整数部分与小数部分。

  • 分数反转是把分母的数反转,再把分子的数反转,不交换分子与分母。

  • 百分数的分子一定是整数,百分数只改变数字部分。

输入格式

一个实数 ss

输出格式

一个实数,即 ss 的反转数

输入输出样例

输入 #1复制

5087462

输出 #1复制

2647805

输入 #2复制

600.084

输出 #2复制

6.48

输入 #3复制

700/27

输出 #3复制

7/72

输入 #4复制

8670%

输出 #4复制

768%

说明/提示

【数据范围】

  • 对于 25% 的数据,s 是整数,不大于 20位;
  • 对于 25% 的数据,s 是小数,整数部分和小数部分均不大于 10 位;
  • 对于 25% 的数据,s 是分数,分子和分母均不大于 10 位;
  • 对于 25% 的数据,s 是百分数,分子不大于 19 位。

【数据保证】

  • 对于整数翻转而言,整数原数和整数新数满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数和原来的数字的最高位数字不应为零。

  • 对于小数翻转而言,其小数点前面部分同上,小数点后面部分的形式,保证满足小数的常见形式,也就是末尾没有多余的 0(小数部分除了 0 没有别的数,那么只保留 1 个 0。若反转之后末尾数字出现 0,请省略多余的 0)

  • 对于分数翻转而言,分数不约分,分子和分母都不是小数。输入的分母不为 0。与整数翻转相关规定见上。

  • 对于百分数翻转而言,见与整数翻转相关内容。

数据不存在负数。

题目解析:

ps:这道题真的要特别细节才能AC!!!想了很久,但是可能我的方法稍微有一点点麻烦,思路比较简单易懂,真的编了好多样例才AC了

大致思路:

         题目中有很多类型的数字类型,因此我们分类讨论,利用find函数查找字符,如果找到了返回第一次出现的下标,如果没找到则返回string::nops(-1)来分类讨论,判断该数是小数、分数还是百分数或者整数,整数是最好处理的,并且输入的字符串中不存在任何的符号,我们把它放在最后的else中,我们可以先把整数的操作搞定,然后测试一下是否正确,再接着讨论下一种情况。

整数部分反转:

  • 负数处理:首先我们不要忘记处理负数,非常简单的办法就是判断字符串第一个字符是否为‘-’,要是为‘-’的话我们直接输出一个'-',之后再把这个字符串当正数处理就好啦,并且我们在reverse中也添加了字符串倒叙存储时不把'-'放进去。
  • 数字反转处理:由于这道题涉及反转数字比较多,还要去除最前面的零,所以我们单独设计一个函数,先将字符串倒序存储在一个新的字符串b中,再用while循环判断是否存在前缀0,若存在则删除,这里我们运用的一个删除操作,erase来处理,并且由于我们删除掉一个字符后,默认n向前继续推动一位,所以我们在while循环中不需要n++。另外,还需要注意的细节是,我们不能删除所有的前缀0,当删到最后一个字符时,就算是0我们也不能继续删除啦,因为再删除就没有啦!!!所以我们在while循环中要考虑边界问题n<lena-1
string reverse(string a,int lena,int flag){
    string b;
     for(int i=lena-1;i>=0;i--){ //将a字符串倒序存储到b中
            if(a[i]!='-'){
                b+=a[i];
            }
        }
        if(flag==1){ //小数部分反转 【去除后缀零】
            int n=lena-1;
            while(n>0&&b[n]=='0'){
                b.erase(n,1);
            }
            
        }
        else{ //整数部分反转 【去除前缀零】
            int n=0;
            while(n<lena-1&b[n]=='0'){
                b.erase(n,1);
            }
        }
    return b;
}

小数反转部分:

  • 小数部分反转处理:小数这部分是最复杂的,因为整数部分反转我们去除前缀0就可以啦,但是小数部分反转正好相反,不能去除前缀0,反而要去除后缀0,所以我在设计reverse函数的时候多加了个flag标记,目的则是区分小数部分和整数部分的反转。
  • 整数和小数处理方法不同:我们可以将有符号的数分成两个字符串,分别处理反转,处理完之后再合并起来输出就好啦。【其余数字类型思路和小数部分相同】
//小数反转
    if(a.find('.')!=string::npos){
        string  c,d;
        int n=a.find('.');//标记小数点符号的位置,方便我们分割字符串
        int x=0;
        while(a[x]!='.') { //将小数点前面整数部分的字符串单独保存在c字符串中
            c+=a[x];
            x++;
        }
        int lenc=c.length(); //便于之后计算d字符串的字符个数以及revers函数的调用
        d=a.substr(n+1,lena-lenc-1);//知道c字符串的长度我们直接就能计算出d字符串的长度,直接用substr函数分割出小数部分
        int lend=d.length();
        c=reverse(c,lenc,0);//整数部分标记为0,表示整数反转
        d=reverse(d,lend,1);//小数部分标记为1,表示小数反转
        b+=c;//将反转好的c,d字符串拼接起来并加上小数点
        b+='.';
        b+=d;

    }

大致思路就是上面这样啦

完整代码如下:

#include<bits/stdc++.h>
using namespace std;
string reverse(string a,int lena,int flag){
    string b;
     for(int i=lena-1;i>=0;i--){ //将a字符串倒序存储到b中
            if(a[i]!='-'){
                b+=a[i];
            }
        }
        if(flag==1){ //小数部分反转 【去除后缀零】
            int n=lena-1;
            while(n>0&&b[n]=='0'){
                b.erase(n,1);
            }
            
        }
        else{ //整数部分反转 【去除前缀零】
            int n=0;
            while(n<lena-1&b[n]=='0'){
                b.erase(n,1);
            }
        }
    return b;
}
int main(){
    string a,b;
    cin>>a;
    int lena=a.length();
    if(a[0]=='-') cout<<'-';
    //小数反转
    if(a.find('.')!=string::npos){
        string  c,d;
        int n=a.find('.');//标记小数点符号的位置,方便我们分割字符串
        int x=0;
        while(a[x]!='.') { //将小数点前面整数部分的字符串单独保存在c字符串中
            c+=a[x];
            x++;
        }
        int lenc=c.length(); //便于之后计算d字符串的字符个数以及revers函数的调用
        d=a.substr(n+1,lena-lenc-1);//知道c字符串的长度我们直接就能计算出d字符串的长度,直接用substr函数分割出小数部分
        int lend=d.length();
        c=reverse(c,lenc,0);//整数部分标记为0,表示整数反转
        d=reverse(d,lend,1);//小数部分标记为1,表示小数反转
        b+=c;//将反转好的c,d字符串拼接起来并加上小数点
        b+='.';
        b+=d;

    }
    //分数反转  
    else if(a.find('/')!=string::npos){
       string c,d;
        int n=a.find('/');
        int x=0;
        while(x!=n){
            c+=a[x];
            x++;
        }
        int lenc=c.length();
        int lend=lena-lenc-1;
        d=a.substr(n+1,lend);
        c=reverse(c,lenc,0);
        d=reverse(d,lend,0);
        b+=c;
        b+='/';
        b+=d;
    }
    
    //百分数反转
    else if(a.find('%')!=string::npos){
       b=a.substr(0,lena-1);
       b=reverse(b,lena-1,0);
       b+='%';
    }
    //整数反转
    else{
        b=reverse(a,lena,0);
    }
    cout<<b<<endl;
    return 0;
}

声明:苯人做得比较复杂 ,如果想要参考更简便高级的解决方法,可以点进这道题的链接去参考题解中大佬们的代码和思路!!!当然也十分欢迎来私信博主交流:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值