P1553 数字反转(升级版)

P1553 数字反转(升级版)

P1553 数字反转(升级版)
思路比较清晰,但是有许多的细节需要处理,这里我们用到字符串处理的相关知识,第一次尝试如下,但是出现了乱码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
	char a[30],b[30];//分别输入字符串数组和输出新的字符串数组
	int flag=1,index=-1,len,f,g;
	cin>>a;//直接输入即可,但是中间不能有空格,换行符,还好本题没有
	len=strlen(a);// cstring 头文件中的计算字符串实际长度的函数,与预设的数组空间无关,数组空间函数用相同头文件下的 sizeof() 函数
	for(int i=0;i<len;i++){
	// flag==1 代表整数(字符串)类型
		if(a[i]=='.'){
			flag=2;// flag 为 2 时表示浮点数
			index=i;//记录小数点位置
			break;//找到符号位就跳出循环
		}
		else if(a[i]=='/'){
			flag=3;
			index=i;
			break;
		}
		else if(a[i]=='%'){
			flag=4;
			//不必记录百分号的位置了,显而易见
			break;
		}
		else;//空语句
	}
	if(flag==1){//处理整型
		f=0;
		if(len==1 && a[0]=='0')
			b[0]='0';//单独考虑为 0 情况
		else{
			for(int i=len-1;i>=0;i--){
				if(a[i]=='0' && f==0);//舍弃 0
				else{
					b[f]=a[i];//将有效的数据存入数组 b
					f++;
				}
			}
		}
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];//输出新的整型
	}
	//注意!注意!这里输出整型时出现了乱码!(如下输出所示)事与愿违(你知道为什么吗?)
	else if(flag==2){
		f=0;
		if(index==1 && a[0]=='0')
			b[0]='0';//小数点之前只有一个 0 时
		else{
			for(int i=index-1;i>=0;i--){
				if(a[i]=='0' && f==0);
				else{
					b[f]=a[i];
					f++;//存放有效的小数点之前的数
				}
			}
		}
		b[f]='.';//存放小数点
		g=f+1;//开始处理小数点后面的数,注意是末尾不能有 0,对应之前的数组进阶小数点的前几位 0 去掉即可
		if(len-index==2 && a[len-1]=='0')
			b[g]='0';//小数点之后仅有一个 0 要保留
		else{
			for(int i=index+1;i<len;i++){
				if(a[i]=='0' && g==f+1);
				else{
					b[g]=a[i];
					g++;
				}
			}
		}
		for(int i=0;i<=f;i++)
			cout<<b[i];
		for(int i=strlen(b)-1;i>f;i--)//注意,由于上面是正序保存原有效数据,所以要逆序输出!
			cout<<b[i];
	}
	else if(flag==3){
		f=0;
		if(index==1 && a[0]=='0')
			b[0]='0';//单独考虑分子为 0
		else{
			for(int i=index-1;i>=0;i--){
				if(a[i]=='0' && f==0);
				else{
					b[f]=a[i];
					f++;//分子倒序
				}
			}
		}
		b[f]='/';
		g=f+1;
		for(int i=len-1;i>index;i--){//分母不可能为一个 0,不予考虑,与浮点数的不同之处还在于新的分母前几位不为 0,也就是原数组的末尾 0 去掉
			if(a[i]=='0' && g==f+1);
			else{
				b[g]=a[i];
				g++;
			}
		}
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];
	}
	else{
		f=0;
		b[0]='0';//为 0% 时发挥作用
		for(int i=len-2;i>=0;i--){
			if(a[i]=='0' && f==0);
			else{
				b[f]=a[i];
				f++;
			}
		}
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];
		cout<<'%';
	}
	return 0;
}

下面是乱码问题:

输入
输出

0
0闌

0%
0闌%

5
5闌

我不是很明白为什么会这样。。。
但有一点可以大致确定,是 strlen( ) 函数的问题
哈哈哈,挺开心的,我找到了原因:原来组成数组 b 的过程中没有在末尾自动添加 ‘\0’,只能手动添加,才能得到正确的 strlen( )! 下面是“改进”的代码(变麻烦了。。):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
	char a[30],b[30],c[30];//分别输入字符串数组和输出新的字符串数组
	//新增数组 c 单独存储符号后面的有效数据
	int flag=1,index=-1,len,f,g;
	cin>>a;//直接输入即可,但是中间不能有空格,换行符,还好本题没有
	len=strlen(a);// cstring 头文件中的计算字符串实际长度的函数,与预设的数组空间无关,数组空间函数用相同头文件下的 sizeof() 函数,以'\0'为结束标志
	for(int i=0;i<len;i++){
	// flag==1 代表整数(字符串)类型
		if(a[i]=='.'){
			flag=2;// flag 为 2 时表示浮点数
			index=i;//记录小数点位置
			break;//找到符号位就跳出循环
		}
		else if(a[i]=='/'){
			flag=3;
			index=i;
			break;
		}
		else if(a[i]=='%'){
			flag=4;
			//不必记录百分号的位置了,显而易见
			break;
		}
		else;//空语句
	}
	if(flag==1){//处理整型
		f=0;
		if(len==1 && a[0]=='0'){
			b[0]='0';//单独考虑为 0 情况
			b[1]='\0';//需要手动添加'\0'
		}
		else{
			for(int i=len-1;i>=0;i--){
				if(a[i]=='0' && f==0);//舍弃 0
				else{
					b[f]=a[i];//将有效的数据存入数组 b
					f++;
				}
			}
			b[f]='\0';
		}
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];
	}
	else if(flag==2){
		f=0;
		if(index==1 && a[0]=='0'){
			b[0]='0';
			b[1]='\0';//小数点之前只有一个 0 时
		}
		else{
			for(int i=index-1;i>=0;i--){
				if(a[i]=='0' && f==0);
				else{
					b[f]=a[i];
					f++;//数组 b 存放有效的小数点之前的数
				}
			}
			b[f]='\0';
		}
		g=0;//开始处理小数点后面的数,注意是末尾不能有 0,对应之前的数组进阶小数点的前几位 0 去掉即可,用数组 c 存储
		if(len-index==2 && a[len-1]=='0'){
			c[g]='0';//小数点之后仅有一个 0 要保留
			c[g+1]='\0';
		}
		else{
			for(int i=index+1;i<len;i++){
				if(a[i]=='0' && g==0);
				else{
					c[g]=a[i];
					g++;
				}
			}
			c[g]='\0';
		}
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];
		cout<<'.';//单独直接输出小数点,不放数组里面了
		for(int i=strlen(c)-1;i>=0;i--)//注意,由于上面是正序保存原有效数据,所以要逆序输出!
			cout<<c[i];
	}
	else if(flag==3){
		f=0;
		if(index==1 && a[0]=='0'){
			b[0]='0';//单独考虑分子为 0
			b[1]='\0';
		}
		else{
			for(int i=index-1;i>=0;i--){
				if(a[i]=='0' && f==0);
				else{
					b[f]=a[i];
					f++;//分子倒序
				}
			}
			b[f]='\0';
		}
		g=0;
		for(int i=len-1;i>index;i--){//分母不可能为一个 0,不予考虑,与浮点数的不同之处还在于新的分母前几位不为 0,也就是原数组的末尾 0 去掉
			if(a[i]=='0' && g==0);
			else{
				c[g]=a[i];
				g++;
			}
		}
		c[g]='\0';
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];
		cout<<'/';
		for(int i=0;i<strlen(c);i++)
			cout<<c[i];
	}
	else{
		f=0;
		if(len==2 && a[0]=='0'){
			b[0]='0';
			b[1]='\0';
		}
		else{
			for(int i=len-2;i>=0;i--){
				if(a[i]=='0' && f==0);
				else{
					b[f]=a[i];
					f++;
				}
			}
			b[f]='\0';
		}
		for(int i=0;i<strlen(b);i++)
			cout<<b[i];
		cout<<'%';
	}
	return 0;
}

过了,但是代码量太大了有木有?学习了如下简便的写法:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
	string s;//直接初始化为字符串类型
	char p=' ';//存放符号
	int len=0;
	cin>>s;
	for(int i=0;i<s.size();i++){
		if(s[i]>='0' && s[i]<='9')
			len++;//统计出现符号之前的数字个数
		else{
			p=s[i];
			break;
		}
	}
	int flag=len;//拷贝一份 len 记录符号位置
	len--;
	while(s[len]=='0' && len>0)
		len--;//倒序寻找 0 ;直到不为 0 跳出循环,这时 len 的值恰好是要输出有效数据的起始位置(倒序输出)
	for(int i=len;i>=0;i--)
		cout<<s[i];
	if(p==' ')
		return 0;//整型的话就完成了,跳出主函数
	else{
		if(p=='%'){
			cout<<p;
			return 0;//百分数的话再输出一个百分号就结束啦
		}
		else
			cout<<p;//下面考虑浮点数与分数后半部分
	}
	int flag0=s.size()-1;
	//对于浮点数,初始数据后半部分可能有 0 ,输出的后半部分末尾不能有 0 ,除非只有 0 要保留一个:
	while(s[flag+1]=='0' && flag<flag0-1)
		flag++;//舍弃要输出的末尾的 0 ,除非只有一个 0
	//对于分数,初始数据分母末尾可能有 0 ,输出的分母开头不能有 0 ,且分母不会只有一个 0:
	while(s[flag0]=='0' && flag0>flag+1)
		flag0--;
	for(int i=flag0;i>flag;i--)
		cout<<s[i];//倒序输出后半部分有效数据
	return 0;
}

一个明智的人就是一个不会被表面现象所欺骗的人,他甚至预见到了事情将往哪一方向变化。——叔本华
希望自己解题时也能洞见本质。。。

上一篇:从SQLFlow的json格式中学习数据血缘json格式设计


下一篇:权属面积批量修改0.1