这道题考了很多字符串的操作,大家可以练习一下,检测自己字符串操作是否熟练
P1553 数字反转(升级版)【出自洛谷】
字符串操作不熟悉的可以参考我的这篇文章,或许对你会有帮助:)
题目背景
以下为原题面,仅供参考:
给定一个数,请将该数各个位上数字反转得到一个新数。
这次与 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;
}
声明:苯人做得比较复杂 ,如果想要参考更简便高级的解决方法,可以点进这道题的链接去参考题解中大佬们的代码和思路!!!当然也十分欢迎来私信博主交流:)