【PAT】第六章 C++标准模板库 - string

string

头文件:#include <string>

ps. 头文件 string.h 和 头文件 cstring 支持 c 语言中的字符串函数,但不支持 c++ 中的 string 类。

1 string 对象的构造

1.1 string str(const char* s)

将字符串初始化为 s 指向的字符串。

string str("hello world!");
2. string(size_type n, char c)

创建一个包含 n 个元素的 string 对象,其中每个元素被初始化为字符 c。

string str(10, 'a');
3. string(const string& str)

将字符串初始化为字符串 str。

string str("hello world!");
string sstr(str);
4. string str

缺省创建一个字符串对象,默认长度为 0。

string str;
5. string str(const char* s, size_type n)

将字符串初始化为 c 字符串 s 的前 n 个字符。如果 n 大于 s 的长度,超出部分可能会出现乱码。

string str("hello world", 50);
6. string str(string::iter.begin(), string::iter.end())
7. string str(const string& str, string size_type pos=0, size_type n=npos)

6.3.2 string的访问

【注】读入和输出 string 只能用 cin 和 cout,但是可以用 printf("%s",str.c_str());

1. 通过下标直接访问
printf("%c",str[1]);
2. 通过迭代器访问

stringvector 的迭代器,支持对迭代器直接进行 加减某个数字

ATTENTION

  • string 的迭代器不需要指明类型,可以直接声明。
string::iterator it;
  • end() 指向的是 最后一个元素的下一个,而非最后一个元素。
#include <cstdio>
#include <string>
using namespace std;

int main()
{
	string str="abcd";
	for(string::iterator it=str.begin();it!=str.end();it++)
		printf("%c",*it);
	return 0;
}

6.3.3 string常用函数

1. operator +=

拼接两个string

【注】string 可以直接和 char 拼接!

str3=str1+str2;
str1+=str2;
str2=str2+'c';
str3='d'+str2;

+ 与 += 的比较
string对象的运算符+和运算符+=效率差很多,+比+=更耗时间更占空间。(因为前者是将两个string的对象相加,并赋给一个新的对象;而后者直接将等号右边的内容追加到左边的string后边。)

+ 的小tip
必须保证每个加法运算符(+)的两侧的运算对象都至少有一个是string。
例如:string str="abc"+"de"; 就会出错,因为 + 会先把等号右边的计算出来,再追加到左边,而等号右边的两个字符串常量无法相加。
同理:str+=str[1]+'a'; 也会出错,因为 char型变量的相加是 ASCII 码相加,所以最后追加到 str 末尾的是 ASCII 码等于 str[1]+'a' 的字符。

2. compare operator

两个 string 可以直接用 ==、!=、<、<=、>、>= 比较大小。默认按字典序比较。

3. length() / size()

length() 返回 string 的长度,即存放的字符数,时间复杂度为O(1)

size()length() 基本相同。

4. insert()

复杂度:O(n)

  • insert(pos,string)
    pos的位置处插入字符串string
  • insert(it,it2,it3)
    it为插入位置,it2it3为要插入字符串的首尾迭代器,表示将串[it2,it3)插入到it位置上。
#include <cstdio>
#include <string>
using namespace std;

int main()
{
	string str="abcxyz",str2="opq";
	str.insert(str.begin()+3,str2.begin(),str2.end());
	return 0;
}
5. erase()

复杂度:O(n)

  • 删除单个元素 - erase(it)
    it为需要删除的元素的迭代器
#include <cstdio>
#include <string>
using namespace std;

int main()
{
	string str="abcxyz";
	str.erase(str.begin()+4);
	return 0;
}
  • 删除一个区间内所有的元素 - erase(first,last)
    firstlast区间的首尾迭代器,即删除[first,last)
#include <cstdio>
#include <string>
using namespace std;

int main()
{
	string str="abcxyz";
	str.erase(str.begin()+4,str.end());
	return 0;
}
  • 删除一个区间内所有的元素 - erase(pos,length)
    pos为删除的起始地址,length为删除的字符个数。
#include <cstdio>
#include <string>
using namespace std;

int main()
{
   string str="abcxyz";
   str.erase(3,2);
   return 0;
}
6. clear()

清空string中的数据,时间复杂度为O(1)

7. substr()
  • substr(pos, len)
    返回从 pos 位置开始,长度为 len 的子串,时间复杂度为 O ( l e n ) O(len) O(len)
  • substr(pos)
    返回从 pos 位置开始到 字符串末尾 的子串,时间复杂度为 O ( s i z e ) O(size) O(size)
8. string::npos

string::npos 是一个常数,本身值为 -1。unsigned_int 类型数据,可以认为是 unsigned_int 类型的最大值。

9. find() - 线性搜索比较
  • str.find(str2)
    str2str 的子串时,返回其在 str第一次 出现的位置,否则返回 string::npos。时间复杂度 O ( s t r . s i z e ( ) ∗ s t r 2. s i z e ( ) ) O(str.size() * str2.size()) O(str.size()str2.size())
  • str.find(str2, pos)
    pos 位置开始匹配 str2,返回其在 之后第一次 出现的位置,否则返回 string::npos。时间复杂度 O ( ( s t r . s i z e ( ) − p o s ) ∗ s t r 2. s i z e ( ) ) O((str.size() - pos) * str2.size()) O((str.size()pos)str2.size())
10.replace()

时间复杂度为O(str2.length())

  • str.replace(pos,len,str2)
    strpos位置开始的长度为len的字串替换成str2
  • str.replace(it1,it2,str2)
    str的迭代器[it1,it2)范围的子串替换为str2
11.atoi()、stoi()、strtol()

atoi()
头文件:#include <cstdlib>
string类型转换为int型。溢出不会报错。遇到非法字符会停止。只能转换为十进制数。

int a=atoi(str.c_str());

stoi()
头文件:#include <string>
string类型转换为int类型。溢出会报错。遇到非法字符会停止。只能转换为十进制数。

int a=stoi(str.c_str());

strtol()
头文件:#include <cstdlib>
stirng类型转换为int类型。溢出不会报错。第三个参数可以设置进制。

int a=strtol(str.c_str(),NULL,radix)
12. to_string()

将数值(int、long long、float、double)转换为字符串,返回到对应的字符串。

str=to_string(111);
13. resize()
  • str.resize(n) - 将字符串长度调整为 n,若 str.size() < n,则在末尾插入默认字符扩展长度;若 str.size() > n,则截断。
  • str.resize(n, c) - 将字符串长度调整为 n,若 str.size() < n,则在末尾插入字符 c 扩展长度;若 str.size() > n,则截断。

6.3.4 例题

【例】A1060 Are They Equal (25 分)

ATTENTION

  • 这道题实际上要做的就是把输入的字符串转换成0.xxxx*10k的形式。但是测试数据很讨厌,有些数据开头有无效零,也有0.0000的数据。
  • 大体思路是分为小于1的数和大于1的数(即去掉先导零以后,第一位是数字还是小数点)处理。前者需要注意的是,有.0000的情况要特别处理。 在计算小数点的时候,因为会遍历字符串,要特别关注有没有下标越界的情况
  • 前者的幂次是负的!!!
#include <string>
#include <iostream>
using namespace std;

int n,k1,k2;
string s1,s2;

int main()
{
	cin>>n>>s1>>s2;
	if(s1=="0"){}
	else
	{
		while(s1[0]=='0')	s1=s1.substr(1,s1.size()-1);
		if(s1[0]=='.') 	//<1的数 找第一个非零的数 
		{
			int p1=0;
			int num=p1+1;
			while(s1[num]=='0'&&num<s1.size()) num++;
			if(num==s1.size())
				s1="0";
			else
			{
				k1=-(num-p1-1);
				s1=s1.substr(num,s1.size()-num); 	//非零位 
			}	
		}
		else
		{
			int p1=0;
			while(s1[p1]!='.'&&p1<s1.size()) p1++;
			k1=p1;
			if(p1!=s1.size())
				s1=s1.substr(0,p1)+s1.substr(p1+1,s1.size()-p1); 
		}
	}
	if(s2=="0"){}
	else
	{
		while(s2[0]=='0')	s2=s2.substr(1,s2.size()-1);
		if(s2[0]=='.') 	//<1的数 找第一个非零的数 
		{
			int p2=0;
			int num=p2+1;
			while(s2[num]=='0') num++;
			if(num==s2.size())
				s2="0";
			else
			{
				k2=-(num-p2-1);
				s2=s2.substr(num,s2.size()-num); 	//非零位 
			}
		}
		else
		{
			int p2=0;
			while(s2[p2]!='.'&&p2<s2.size()) p2++;
			k2=p2;
			if(p2!=s2.size())
				s2=s2.substr(0,p2)+s2.substr(p2+1,s2.size()-p2); 
		}
	}
	if(s1.size()<n)
		for(int i=0;i<n;i++)
			s1=s1+'0';
	if(s2.size()<n)
		for(int i=0;i<n;i++)
			s2=s2+'0';
	if(k1!=k2)
	{
		cout<<"NO"<<" 0.";
		for(int i=0;i<n;i++)
			cout<<s1[i];
		cout<<"*10^"<<k1<<" 0.";
		for(int i=0;i<n;i++)
			cout<<s2[i];
		cout<<"*10^"<<k2;
		return 0;
	}
	else
	{
		for(int i=0;i<n;i++)
			if(s1[i]!=s2[i])
			{
				cout<<"NO"<<" 0.";
				for(int i=0;i<n;i++)
					cout<<s1[i];
				cout<<"*10^"<<k1<<" 0.";
				for(int i=0;i<n;i++)
					cout<<s2[i];
				cout<<"*10^"<<k2;
				return 0;
			}
		cout<<"YES"<<" 0.";
		for(int i=0;i<n;i++)
			cout<<s1[i];
		cout<<"*10^"<<k1;
	}
}

【例】*A1100 Mars Numbers (20 分)

ATTENTION

  • 这道题麻烦就麻烦在13的整数倍0的处理
    对于13的整数倍,并不是像十进制那样,输出10/20等等,而是只输出十位数
  • 所以,在自然数转火星文时,判断自然数num是否大于等于13。如果小于13,则一定是一位火星文。如果大于13,再判断num/13是否为0,如果是0,只输出十位,否则要输出十位和个位。
  • 还有需要注意的是,在处理进制转换时,使用while(num)一定要特别处理num=0的情况!!!
  • 火星文转自然数时,根据火星文的长度判断是两位数还是一位数。注意tret是三个字符啊啊啊!!!还要注意空格哇哇哇!!!
  • 由于输入可能有空格,所以不能用cin,用getline哈。然后用getline的话,记得用getchar吞到前面那个cin遗留下来的换行符。

cin>>str;
遇到空格、tab、回车等空白符即结束读入

getline(cin,str);
头文件:#include < string > ,可接受空白符并输出

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
using namespace std;

const string ge[13]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"};
const string higher[13]={"","tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};

int n;

int main()
{
	cin>>n;
	getchar(); 	//
	for(int i=0;i<n;i++)
	{
		string str;
		getline(cin,str); 	//getline 
		//数字转火星文  柳神的办法更好! 
		if(str[0]>='0'&&str[0]<='9')
		{
			int num=0;
			for(int j=0;j<str.size();j++)
				num=num*10+(str[j]-'0');
			bool flag=false;
			vector<string> ans;
			if(num==13)
				ans.push_back(higher[1]);
			else
			{
				if(num==0) 	//!!!
					ans.push_back(ge[0]); 
				while(num)
				{
					int cur=num%13;
					num/=13;
					if(!flag)
					{
						if(cur!=0)
							ans.push_back(ge[cur]);
						flag=true;
					}
					else
						ans.push_back(higher[cur]);
				}
			}
			
			for(int j=ans.size()-1;j>=0;j--)
			{
				if(j!=0)
					cout<<ans[j]<<" ";
				else
					cout<<ans[j];
			}
			cout<<endl;
		}
		else 	//火星文转数字 
		{ 
			int res=0;
			if(str.size()>4) 	//两位火星文 
			{
				string s1=str.substr(0,3);
				for(int j=0;j<13;j++)
				{
					if(higher[j]==s1)
						res=j*13;
				}
				string s2=str.substr(4,str.size()-4);
				for(int j=0;j<13;j++)
				{
					if(ge[j]==s2)
						res+=j;
				}
			}
			else 	//一位 
			{
				for(int j=0;j<13;j++)
				{
					if(higher[j]==str)
						res=j*13;
				}
				for(int j=0;j<13;j++)
				{
					if(ge[j]==str)
						res+=j;
				}
			}
			cout<<res<<endl;
		}
	}
	return 0;
}

【例】*A1084 Broken Keyboard (20 分)

worn out 疲惫不堪的;耗尽的
original a.原来的,开始的
typed-out 输入
detect v.检测
captilize vt. 用大写字母写或印刷;

ATTENTION

  • 大小写不敏感。
  • 按检测到的顺序输出
  • 其实不用存储在vector中,直接输出就行了。
  • 柳神使用的str.find()。对于s1中的每个字符,在s2和ans中进行查找,如果他在s2中找不到,并且他的大写形式在ans中找不到的话,说明第一次遇到这个worn out键,把他加入ans中。最后输出ans即可。
#include <iostream>
#include <string>
#include <vector> 
#include <set> 	//有序的 不行 需要无序的 
using namespace std;

string s1,s2;
bool vis[100]={0}; 	//0-9 A-Z _
vector<char> ans;

int main()
{
	cin>>s1>>s2;
	for(int i=0;i<s2.size();i++)
	{
		if(s2[i]>='a'&&s2[i]<='z')
			s2[i]=s2[i]-'a'+'A';
		if(s2[i]>='0'&&s2[i]<='9')
			vis[s2[i]-'0']=1;
		else if(s2[i]>='A'&&s2[i]<='Z')
			vis[s2[i]-'A'+20]=1;
		else
			vis[50]=1;
	}
	for(int i=0;i<s1.size();i++)
	{
		int idx=0;
		if(s1[i]>='a'&&s1[i]<='z')
			s1[i]=s1[i]-'a'+'A';
		if(s1[i]>='0'&&s1[i]<='9')
			idx=s1[i]-'0';
		else if(s1[i]>='A'&&s1[i]<='Z')
			idx=s1[i]-'A'+20;
		else
			idx=50;
		if(vis[idx]==0)
		{
			ans.push_back(s1[i]);
			vis[idx]=1;
		}
	}
	for(int i=0;i<ans.size();i++)
		cout<<ans[i];
	return 0;
}

【例】*A1132 Cut Integer (20 分)

an even number 偶数
an odd number 奇数

ATTENTION

  • substr(起始位置,子串长度);
  • int a = stoi(str);
#include <iostream>
#include <string>
//#include <cstdio>
using namespace std;

int n;
string str;

int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>str;
		int len=str.size()/2;
		int a=stoi(str.substr(0,len));
		int b=stoi(str.substr(len,len));
		//printf("%d",stoi(str.substr(len,len).c_str()));
		int c=stoi(str);
		if(a*b!=0&&c%(a*b)==0)
			cout<<"Yes\n";
		else
			cout<<"No\n";
	}
	return 0;
}

【例】*A1140 Look-and-say Sequence (20 分)

Look-and-say 看图说话

ATTENTION

  • string+=会比+快很多很多,空间也会省很多很多。 这道题用=会超时。
  • 获取一个字符串连续数字的个数:将pre初始化为字符串的第一个字符,并且将 cnt初始化为0(因为第一个字符还会被比较一次,所以初始化为0)。遍历字符串,直到遇到一个不同的字符,此时前一个字符的数量就是cnt,保存。并且更新pre为当前字符,cnt为1,当前字符也要被计算。继续遍历即可。对于最后一串相同的字符,需要在循环结束后对齐保存
char pre=str1[0];
int cnt=0;	
for(int i=0;i<str1.size();i++)
{
	if(str1[i]==pre)
		cnt++;
	else
	{
		pre=str1[i];
		str2=str2+str1[i-1]+(char)(cnt+'0');
		cnt=1;
	}
}
str2=str2+str1[str1.size()-1]+(char)(cnt+'0');
  • 记一下数字转string的函数:to_string(x)。很实用。
  • 这道题的题干难读.jpg
  • 表示依旧不懂为什么题目里说了D不为1,样例里D就为1了orz…This definition works for D = 1 as well. …艹
#include <iostream>
#include <string>
using namespace std;


int n;
string str1,str2;

int main()
{
	ios::sync_with_stdio(false);
	cin>>str1>>n;
	n--;
	while(n--)
	{
		str2="";
		int idx=0;
		while(idx<str1.size())
		{
			int i;
			for(i=idx+1;i<str1.size();i++)
			{
				if(str1[i]!=str1[idx])
					break;
			}
			int cnt=i-idx;
			//str2=str2+str1[idx]+(char)(cnt+'0');
			str2+=str1[idx]+to_string(cnt);
			//str2+=str1[idx];
			//str2+=(char)(cnt+'0');
			idx+=cnt;
		}
		str1=str2;
	}
	cout<<str1<<endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值