《算法笔记》学习日记——6.3 string的常见用法详解

6.3 string的常见用法详解

Codeup Contest ID:100000598

问题 A: 字符串处理(题库问题造成的答案错误 )

题目描述
读入两个字符串,字符串除了数字还可能包括 ‘—’、‘E’、‘e’、’.’,相加之后输出结果,如果是浮点型,要求用科学计数法表示(最多包含10个有效数字)。
输入
输入包含多组测试数据。
每组输入占两行,每行一个字符串,测试数据保证字符串的构成严格按照题目中的描述。
输出
输出两个数字相加的结果,每组输出占一行。
样例输入

34.56
2.45e2

样例输出

2.7956e2

思路
写了一个下午,实在不知道哪儿错了,ityanger的AC代码确实能AC,但是也有错误的地方(当输入1和1.245e-2时,输出是1.1245e0),不知道Codeup的测试点是在哪。

2020.4.2傍晚补充:我把题库买了,原来题库里判定的输出就是跳0的操作(输入1和1.245e-2,输出1.1245e0),醉了……我的代码有一个不足的地方就是大整数还是会输出科学计数法,所以第一块的内容还需要改一下(目前的第一块内容只处理了小数点太多自动输出科学计数法的问题),改好了我会更新的哈。

2020.4.2晚补充:代码已经更新了哈,我已经测试过了,所有题库给的数据输出都是正确的(除了跳0的那一部分,那部分是题库里数据有问题),当然,因为to_string和stringstream都有精度问题(体现在输入小数点后位数过多的情况,此时两者都存在精度问题,但是如果用科学计数法输入的话,to_string有精度问题而stringstream没有),所以,如果输入太大或者太小的数,无论是to_string还是stringstream转换出来的输出都有问题。

大家可以看一下这个坑爹的题库(左边是答案输出,右边是我的输出):
在这里插入图片描述
这是光标输出数据对应的两个输入(第三行是我程序的输出):
在这里插入图片描述
我的思路是定义double型的两个数,输入之后把他们的和转化为string类型(因为double型会自动识别科学计数法进行计算,所以就只需要对加法后的结果进行操作)。这里有三种情况:①小数点位数过多,double型自动输出科学计数法,但是默认的科学计数法是带正号和0的(比如样例的默认计数法输出是2.7956e+002),所以也要处理;②普通输出小数的情况需要处理使其输出科学计数法;③整数不用科学计数法输出。

我这里第二种情况修改成了如果是100就不输出e了(比如输入1和1.245e-2输出1.01245,并没有输出1.01245e0),虽然还是错的……(补充:看了以上题库的输出的话,应该是要求输出e0的

另外,如果用C++11的to_string函数的话,转化的精度只有6位,如果想要精度更高,需要用stringstream来对double型数据进行转换。

在这里我把那份AC代码和我的代码都放上来吧,但是那份AC代码我没仔细看,想要看详细注释的可以看这篇博文:
codeup字符串处理problem A 1983
代码

  • 能在CodeupAC的代码
#include<stdio.h>
int main()
{
    char str1[50],str2[50];
    long long s,s1,s2,ans;
    int i,a1,a2,a,b,c,w,flag;
    while(scanf("%s %s",str1,str2)!=EOF){
        s1=s2=flag=b=c=a1=0;
        for(i=0;str1[i];i++){
            if(str1[i]=='-')
                flag=1;
            else if(str1[i]=='.')
                c=1;
            else if(str1[i]=='e'||str1[i]=='E'){
                sscanf(str1+i+1,"%d",&b);
                a1+=b;
                break;
            }
            else{
                s1=s1*10+str1[i]-'0';
                a1-=c;
            }
        }
        if(flag) s1=-s1;
        flag=b=c=a2=0;
        for(i=0;str2[i];i++){
            if(str2[i]=='-')
                flag=1;
            else if(str2[i]=='.')
                c=1;
            else if(str2[i]=='e'||str2[i]=='E'){
                sscanf(str2+i+1,"%d",&b);
                a2+=b;
                break;
            }
            else{
                s2=s2*10+str2[i]-'0';
                a2-=c;
            }
        }
        if(flag) s2=-s2;
        if(a1<a2)
            for(;a1<a2;a2--)
                s2*=10;
        else if(a1>a2)
            for(;a1>a2;a1--)
                s1*=10;
        a=a1;s=s1+s2;
        if(!s){
            printf("0\n");
            continue;
        }
        while(a<0&&s%10==0){
            s/=10;
            a++;
        }
        if(a>=0){
            printf("%lld",s);
            for(i=0;i<a;i++)
                printf("0");
            printf("\n");
            continue;
        }
        flag=0;
        if(s<0){
            s=-s;
            flag=1;
        }
        ans=1;w=0;
        while(ans<=s){
            ans*=10;
            w++;
        }
        if(ans>1){
            ans/=10;
			w--;
        }
        if(flag)
            printf("-");
        printf("%lld",s/ans);
        if(ans>1)
            printf(".%lld",s%ans);
        printf("e%d\n",a+w);
    }
    return 0;
}
  • 我的代码(已修改,除了跳0部分的数据输出,其他输出都是对的)
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<string>
#include<iostream>
#include<iomanip>
#include<sstream>
//#include<fstream> 
using namespace std;
int main(){
	double a, b;
	while(cin>>a>>b){
		stringstream s;//使用stringstream,控制转换为字符串后的有效数字能达到10位 
		s<<setprecision(10)<<a+b;
		string str = s.str();
		//判断是否是大整数//
		bool integer = false;
		//判断是否是整数,因为stringstream会自动科学计数法
		//然而to_string虽然能完整保存整数,但是又有精度问题(小数点后一定只有6位,而且小数点位数过多to_string直接是0)
		string sss = to_string(a+b);
		int PointPosition = sss.find(".");//标记小数点的位置
		int cntzero = 0;//数0的个数 
		for(int i=PointPosition+1;i<sss.length();i++) if(sss[i]=='0') cntzero++;
		if(cntzero==sss.length()-1-PointPosition && sss[0]!='0' || str[0]=='0' && str.length()==1){
		//保证不是因为精度问题而输出0.000000的情况,但又不能把本来就是0的情况排除
			integer = true;//如果小数点之后全是0,就是大整数
			sss.erase(PointPosition, sss.length()-PointPosition);//删除小数点和后面的0 
		}
		///
		//ofstream ofs;
		//ofs.open("C:\\Users\\kykj\\Desktop\\aaaa.txt", ios::out|ios::app);
		string temp = "e";//用于处理e及后面的数字 
		if(str.find("e") != string::npos && integer==false){//如果自动输出了科学计数法,且是小数 
			int pos = str.find("e");//记录e的位置
			int pos2 = 0;//记录e后面第一个非0数的位置
			bool flag = false;//记录是否是负号 
			string tmp;
			for(int i=pos+1;i<str.length();i++){
				if(str[i]=='-'){
					flag = true;
					continue;
				}
				if(str[i]!='0'){
					pos2 = i;
					break;
				}
			}
			if(flag==true) str.erase(pos+2, pos2-(pos+2));
			else str.erase(pos+1,pos2-(pos+1));
			//ofs<<str<<endl;
			cout<<str<<endl;
		}
		else if(str.find(".") != string::npos && integer==false){//如果相加之后是浮点型
			bool flag = false;//默认不是负数
			bool dot = false;
			int pos = str.find(".");//记录小数点所在的位置 
			int ff = 0;//记录第一个非0数字出现的位置 
			str.erase(str.begin()+pos);//删除小数点
			if(str[0]=='-'){
				flag = true;//如果true,表明结果是个负数
				str.erase(str.begin());//把负号先删了 
			} 
			for(int i=0;i<str.length();i++){
				if(str[i]!='0'){
					ff = i;
					str.erase(0, i);//删除前面多余的0 
					break;
				}
			}
			if(str.length()==1) dot = true;//只有一位有效数字 
			if(dot==false) str.insert(1, ".");//如果不止一位有效数字,则直接在第一个数后面插入小数点
			if(flag==true){
				ff = ff+1+1;//如果是负数,ff加上原本删去的负号和小数点
				str.insert(0, "-");//放回负号 
			}
			else ff = ff+1;//如果是非负数,则只加上原来的小数点即可 
			if(pos-ff>=0){
				string num = to_string(pos-ff);
				temp += num;
				str += temp;
			}
			else{
				temp += "-";
				string num = to_string(abs(pos-ff));
				temp += num;
				str += temp;
			}
			//ofs<<str<<endl;
			cout<<str<<endl;
		}
		else{//如果不是浮点型
			//ofs<<sss<<endl;
			cout<<sss<<endl;//这里输出to_string后的sss 
		}
		//ofs.close();
	}
	return 0;
}

小结

C++的string用起来确实非常方便,尤其是插入和删除操作(感觉这两个是最常用的),和C的字符数组相比便捷了很多,而且在C++11里面也有to_string这种函数能直接把数值类型转换成字符串类型,但是好像字符串类型转数值类型没有封装好的函数,只能用atoi或者stringstream的方法?(大概)
详细方法可以看下面这篇博文:
C++中string转int
2020.4.29补充】C++11里有直接的string转其他类型的函数,诸如stoi(string->int)、stod(string->double)、stoll(string->long long)等等。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值