字符串教程
一、什么是字符串
在C++语言中,没有专门的字符串类型,一个字符串,其实就是一个字符数组。不过并不是数组中的所有字符都是字符串的一部分,字符串是以字符“\0”表示字符串的结束的。所以在字符数组中,所有在字符\0之前的字符才是字符串中的有效字符。
字符串也有字面常量,其形式是用双引号包围起来一串字符。例如:
"Hello World";
前面讲到的字符,用的是单引号,字符串用的是双引号,这点不要弄反了。"a"是一个字符串,而不是一个字符,虽然这个字符串只有一个有效字符。
上面定义了一个字符串,其存储形式如图1.1所示。
每一个字符串,后面都有一个不可见的字符“\0”,这个字符是字符串的结束标志。
二、C++字符串String类型
A、加头文件:
C++的String类里面包含了很多字符串处理函数,在使用String类之前我们必须包含下面头文件
#include<string>
B、定义string字符串
声明一个C++string字符串变量很简单:
string Str;
这样我们就声明了一个字符串变量。
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s="hehe";
cout<<s<<endl;
return 0;
}
输出:hehe
C:输入输出
补充说明:
1) scanf()不可以读入 string 类变量。可以先读入字符数组(c 风格),再赋值给 string。
2) printf()不可以输出 steing 类变量,但可以用”c_str()”成员函数转换成 c 风格字符串再
输出,比如:printf(“%s”, s.c_str() );
3) 流可以直接输入输出 C++或 C 风格的两种的字符串。在速度不要求太高时,建议用
流。
4) 输入一般以空格为分隔符。
D:常用函数
1、比较函数:C++字符串支持常见的比较操作符(>,>=,<,<=,==,!=),甚至支持string与C-string的比较(如 str<”hello”)。在使用>,>=,<,<=这些操作符的时候是根据“当前字符特性”将字符按字典顺序进行逐一得比较。字典排序靠前的字符小,比较的顺序是从前向后比较,遇到不相等的字符就按这个位置上的两个字符的比较结果确定两个字符串的大小。
例如:
#include <string>
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s1 = "abcdefg";
string s2 = "abcdefg";
if (s1==s2)cout<<"s1 == s2"<<endl;
else cout<<"s1 != s2"<<endl;
return 0;
}
输出:s1==s2
2、size(),length() 返回字符数量
#include <string>
#include <iostream>
using namespace std;
void main()
{
string s = "abcdefg";
cout<<s.size()<<endl;
cout<<s.length()<<endl;
return 0;
}
3、 empty() 判断字符串是否为空
#include <string>
#include <iostream>
using namespace std;
void main()
{
string s ;
if (s.empty())
cout<<"s 为空."<<endl;
else
cout<<"s 不为空."<<endl;
s = s + "abcdefg";
if (s.empty())
cout<<"s 为空."<<endl;
else
cout<<"s 不为空."<<endl;
cin.get();
}
4、swap字符串交换函数
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s1 = "hehe";
string s2 = "gagaga";
cout<<"s1 : "<<s1<<endl;
cout<<"s2 : "<<s2<<endl;
s1.swap(s2);
cout<<"s1 : "<<s1<<endl;
cout<<"s2 : "<<s2<<endl;
return 0;
}
输出:s1:hehe
s2:gagaga
s1:gagaga
s2:hehe
5、+=在尾部添加字符
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s = "hello";
s += " world";
cout<<s<<endl;
return 0;
}
输出:hello world
6、insert(插入的开始位置,插入字符串) 插入字符.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s = "hehe";
s.insert(0,"头部"); //在头部插入
s.insert(s.size(),"尾部"); //在尾部插入
s.insert(s.size()/2,"中间");//在中间插入
cout<<s<<endl;
return 0;
}
输出:头部he中间he尾部
7、erase删除函数:
erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
#include <string>
using namespace std;
int main ()
{
string str ="This is an example phrase.";
str.erase (10,8); // 第(1)种用法
cout << str << endl; // "This is an phrase."
return 0;
}
8、clear() 删除全部字符
#include <string>
#include <iostream>
using namespace std;
void main()
{
string s = "abcdefg";
cout<<s.length()<<endl;
s.clear();
cout<<s.length()<<endl;
//使用earse方法变相全删除
s = "dkjfd";
cout<<s.length()<<endl;
s.erase(0,s.length());
cout<<s.length()<<endl;
return 0;
}
9 、replace() 替换字符
#include <string>
#include <iostream>
using namespace std;
void main()
{
string s = "abcdefg";
s.replace(2,3,"!!!!!");//从索引2开始3个字节的字符全替换成"!!!!!"
cout<<s<<endl;
return 0;
}
10、substr(起始位置,长度)
#include<string>
#include<iostream>
using namespace std;
main()
{
string s="12345asdf";
string a=s.substr(0,4); //获得字符串s中 从第0位开始的长度为4的字符串
cout<<a<<endl;
}
输出结果为:1234
11、find查找函数:查找成功时返回所在位置,失败返回string::npos的值。
int find(string &s, int pos = 0) ;//从pos开始查找字符串s在当前串中的位置
实例1:
#include<iostream>
using namespace std;
int main()
{
string s="1a2b3c4d5e6f7g8h9i1a2b3c4d5e6f7g8ha9i";
string flag;
string str;
cin>>str;
int position=s.find(str); //find 函数 返回str变量 在s 中的下标位置
if (position != s.npos) //如果没找到,返回一个特别的标志c++中用npos表示,这里npos取值是4294967295,
{
cout << "position is : " << position << endl;
}
else
cout << "Not found the flag" ;
return 0;
}
输入:jk
输出:Not found the flag
输入:2
输出:2
实例2:
#include<iostream>
using namespace std;
int main()
{
string s="1a2b3c4d5e6f7g8h9i1a2b3c4d5e6f7g8ha9i";
string flag;
int position=s.find("2",3); //find 函数 返回”2”在s 中的下标位置
if (position != s.npos) //如果没找到,返回一个特别的标志c++中用npos表示,这里npos取值是4294967295,
{
cout << "position is : " << position << endl;
}
else
cout << "Not found the flag:" ;
return 0;
}
输出:20
习题:
第1题 小X数字母 查看测评数据信息
题目描述
小X喜欢研究字符串。
这天,小X随手在草稿纸上写下了一个大写字母字符串。此时,班长把成绩报告单发到了每位同学的手中。小X看到自己每门都是A (优秀),非常高兴,灵光一闪想到一个问题:
在刚刚写下的字符串中,字母A最多连续出现了多少次呢?
小X立刻数了起来,但这个字符串实在是太长了,希望你帮帮他。
输入
第一行包含一个整数N,表示字符串长度。
第二行包含一个字符串。
数据范围
对于30%的数据,N≤100。
对于60%的数据,N≤1000。
对于 100%的数据,1≤N≤100000。
输出
第一行包含一个整数,表示该字符串中字母A最多连续出现的次数。
样例输入
5
BAACA
样例输出
2
#include<bits/stdc++.h>
using namespace std;
long long n,sum=0,maxx;
int main(){
cin>>n;
char s[n+1];
for(int i=0;i<n;i++){
cin>>s[i];
if(s[i]=='A'){sum++;
maxx=max(sum,maxx);}
else sum=0;
}
cout<<maxx;
return 0;
}
第2题 扑克牌游戏 查看测评数据信息
扑克牌有 13 种代表不同点数的牌(不考虑花色),如下图所示,从左到右依次为“A”,“2”,“3”,“4”,......,“10”,“J”,“Q”,“K”。
小华正在玩一个扑克牌的游戏,在这个游戏中,每种点数的牌都有一个分数(不一定 跟点数相同)。现在小华手上已经有n张扑克牌,他还可以挑选m张扑克牌,使得n+m张扑克牌的总分数最大。我们假定每种点数的扑克牌有无穷多张。
请编程计算小华在游戏中可以最多获得多少分?
输入格式
输入共3行。
第1行13个整数,依次表示每种点数的牌所代表的分数。
第2行两个整数n和m,表示小华已经有n张扑克牌,还可以挑选m张扑克牌。
第3行输入表示小华手上已经有的n张扑克牌的情况,输入的两张扑克牌信息之间没有空格分隔
输出格式
输出共 1 行。
输出一个整数,表示小华在游戏中可以获得的最大分数。
注意:小华选牌的方案可能不唯一,但只要总分数最大即可,不需要输出选牌的方案
输入/输出例子1
输入:
样例1:
1 3 1 1 1 1 2 3 4 1 3 0 1
3 2
234
样例2:
1 3 1 1 1 1 2 3 4 1 5 0 1
3 2
A3Q
样例3:
1 3 1 1 1 1 2 3 4 1 3 0 5
3 2
A10K
输出:
样例1:
13
样例2:
12
样例3:
17
样例解释
【样例1解释】
小华原来手上有3张牌,分别为“2”,“3”,“4”,对应的分数之和为3+1+1=5,他可以再挑选2张扑克牌,都是点数为“9”的扑克牌,这2张牌的分数之和为4+4=8,所以小华 的总得分为13分。
【样例2解释】
小华原来手上有3张牌,分别为“A”,“3”,“Q”,对应的分数之和为1+1+0=2,他可以再挑选2张扑克牌,都是点数为“J”的扑克牌,这2张牌的分数之和为5+5=10,所以小华的总得分为12分。
【样例3解释】
小华原来手上有3张牌,分别为“A”,“10”,“K”,对应的分数之和为1+1+5=7,他可以再挑选2张扑克牌,都是点数为“K”的扑克牌,这2张牌的分数之和为5+5=10,所以小华的总得分为17分。
【数据范围约定】
50%的测试点输入数据保证小华手上已经有的牌中不会出现“A”、“10”、“J”、“Q”、“K” 这5种点数的牌。
80%的测试点输入数据保证小华手上已经有的牌中不会出现“10”这种点数的牌。
100%的测试点输入数据保证 1≤n≤100,0≤m≤100,0≤每种点数的牌所代表的分数 ≤1000。
#include<bits/stdc++.h>
using namespace std;
string x;
long long n,m,c[130],maxx=0,sum=0;
string s="A234567890JQK";
int main(){
for(int i=0;i<=13-1;i++){
cin>>c[i];
if(c[i]>maxx)maxx=c[i];
}
cin>>n;
cin>>m;
cin>>x;
for(int i=0;i<x.length();i++){
if(x[i]=='1')x.erase(i,1);
sum=sum+c[s.find(x[i])];
}
cout<<sum+maxx*m;
return 0;
}
第3题 字母统计(nhoixj2013) 查看测评数据信息
题目描述
晨晨刚上幼儿园,对字母很感兴趣,特别是对‘b’、‘B’、‘m’、‘M’四个字母感觉很亲切,因为这四个字母很像“爸”、“妈”的发音。每次看到一段英文文章,她都要数一数文章里面有多少个上面四个字母。由于她刚学数数,数不准,想让大哥哥、大姐姐帮她数一下,你能帮她吗?
输入
一行:输入一段以‘#‘结束的字符串。
输出0
一行:一个整数代表字符串出现了多少个‘b’、‘B’、‘m’、‘M’字母。
样例输入
Thanks for being there, mom. Happy Mother’s Day.#
样例输出
4
提示
数据范围:
对于80%的数据,字符串长度小于255;
对于100%的数据,字符串长度小于1000;
#include<bits/stdc++.h>
using namespace std;
long long sum=0;
string s;
int main(){
getline(cin,s);
for(int i=0;i<s.size();i++){
if(s[i]=='b'||s[i]=='m'||s[i]=='B'||s[i]=='M')sum++;
}
cout<<sum;
return 0;
}
第4题 动物简介 查看测评数据信息
题目描述
到了动物园,琦琦开心得跳起来。哗,这里好多动物呀,有老虎,有狮子……,在开心之余,琦琦也不忘妈妈的教导:观察动物时要认真仔细,还要看动物园附上的动物简介呀。
动物的简介原来还有英文版的呢!为了卖弄自己的英文水平,琦琦就告诉妈妈每张动物简介里出现了多少次该动物的名称。注意:琦琦只认识小写字母,而且只要是某部分连续的字母同动物名称完全一样,她就会认为这就是那动物的名称,因此当简介中同时出现了monkeys、smonkey、smonkeys时,她就会说出现了3个猴子的名称。
你能编程完成琦琦的任务吗?
输入
第1行为数字n(n<=3000),表示该动物的简介共有n行。
第2行为一个单词,表示琦琦认识的动物名称。
接着是n行,每行为一个长度小于250个字符的字符串,表示动物的简介。
输出
输出文件共1行,为简介里出现了多
少次琦琦能识别出的动物的单词。
样例输入
样例一:
1
monkey
She often jumps onto my knees. I like to give her a bath.
样例二:
2
snake
The snake is a long and thin animal.
Snakes have no legs or feet.
样例输出
样例一:
0
样例二:
1
#include<bits/stdc++.h>
using namespace std;
int n,sum;
string x,s;
int main(){
cin>>n>>x;
getline(cin,s);
for(int i=0;i<n;i++){
getline(cin,s);
for(int j=0;j<=s.size()-x.size();j++)
if(s.substr(j,x.size())==x)
sum++;
}
cout<<sum;
return 0;
}
第5题 棋子(dloixj2020) 查看测评数据信息
题目描述
棋盘从左往右分成 N 个格子。 棋盘上有且仅有 1 只白色棋子 (‘W’表示白旗) 和零个或多个黑色棋子 (‘B’表示黑旗)。在游戏开始时,白棋放置在棋盘的第 1 个格子上,黑棋放置在其他格子上,一个棋子占据一个格子。没有棋子的格子为空(用‘-’表示)。
FJ 然后开始移动白棋,他的每一步都可以做以下两件事之一(不能做其他事):
1、如果白旗的右邻居格子为空,FJ 会将白棋向右移动一个格子。
2、如果白旗的右邻居格子是黑棋,且该黑棋的右邻居为空,那么 FJ 会将白棋移动到该黑棋的右邻居。
FJ 一直重复上述操作,直到不能移动为止。
给定棋盘的初始状态,请输出游戏的最终状态。
输入
一个长度不超过 50 的字符串 S,表示棋盘的初始状态。‘W’表示白旗,‘B’表示黑旗,-’表示空格子。
输出
一个字符串,表示棋盘的最终状态。
样例输入
样例一:
WB-B-B-
样例二:
W--BB---
样例三:
W
样例四:
W-B--B---BB-
样例输出
样例一:
-B-B-BW
样例二:
--WBB---
样例三:
W
样例四:
--B--B--WBB-
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
cin>>s;
int n=s.length();
int w=0;
for(int i=0;i<n;i++){
if(s[i]=='W'){
w=i;
break;
}
}
while(w<n-1){
if(s[w+1]=='-'){
swap(s[w],s[w+1]);
w++;
}
else if(w<n-2&&s[w+1]=='B'&&s[w+2]=='-'){
swap(s[w],s[w+2]);
w+=2;
}
else break;
}
cout<<s;
return 0;
}
第6题 FJ的字符串 查看测评数据信息
FJ在沙盘上写了这样一些字符串:
A1 = “A”
A2 = “ABA”
A3 = “ABACABA”
A4 = “ABACABADABACABA”
… …
你能找出其中的规律并写所有的数列AN吗?
输入
仅有一个数:N ≤ 26。
输出
请输出相应的字符串AN,以一个换行符结束。输出中不得含有多余的空格或换行、回车符
样例输入
3
样例输出
ABACABA
#include<bits/stdc++.h>
using namespace std;
int n;
string s;
char c;
int main(){
cin>>n;
c='A';
for(int i=1;i<=n;++i){
s=s+c+s;
c++;
}
cout<<s;
return 0;
}
第7题 fj散步 查看测评数据信息
Farmer John 出门沿着马路散步,但是他现在发现可能迷路了!
沿路有一排共 N 个农场(1<=N<=100)。不幸的是农场并没有编号,这使得 Farmer John 难以分辨他在这条路上所处的位置。然而,每个农场都沿路设有一个彩色的邮箱,所以 Farmer John 希望能够通过查看最近的几个邮箱的颜色来唯一确定他所在的位置。每个邮箱的颜色用 A..Z 之间的一个字母来指定,所以沿着道路的
N 个邮箱的序列可以用一个长为 N 的由字母 A..Z 组成的字符串来表示。某些邮箱可能会有相同的颜色。Farmer John 想要知道最小的 K 的值,使得他查看任意连续 K个邮箱序列,他都可以唯一确定这一序列在道路上的位置。
例如,假设沿路的邮箱序列为 'ABCDABC' 。Farmer John 不能令 K=3,因为如果他看到了 'ABC',沿路有两个这一连续颜色序列可能所在的位置。最小可行的 K 的值为 K=4,因为如果他查看任意连续 4 个邮箱,这一颜色序列可以唯一确定他在道路上的位置。
输入
输入的第一行包含 N,第二行包含一个由 N 个字符组成的字符串,每个字符均在 A..Z 之内。
输出
输出一行,包含一个整数,为可以解决 Farmer John 的问题的最小 K 值
样例输入
7
ABCDABC
样例输出
4
#include<bits/stdc++.h>
using namespace std;
string s,a;
int n,flag;
int main(){
cin>>n>>s;
for(int i=1;i<=n;i++){
flag=0;
for(int j=0;j<n;j++){
a="";
for(int k=j;k<j+i;k++)a+=s[k];
if(s.find(a,j+1)!=-1){
flag=1;
break;
}
}
if(flag==0){
cout<<i;
break;
}
}
return 0;
}
小华的寒假作业上,有这样一个趣味填空题: 给出用等号连接的两个整数,如“1234=127”。当然,现在这个等号是不成立的。题目让你在左边的整数中间某个位置插入一个加号,看有没有可能让等号成立。以上面的式子为例,如果写成123+4=127,这就可以了。 请你编写一个程序来解决它。
输入
只有那个不相等的式子。已知,等号两边的整数都不会超过2000000000
输出
如果存在这样的方案,请输出那个正确的式子。如果不存在解决方案,请输出“Impossible!”(引号中的部分)。
样例输入
1234=127
样例输出
123+4=127
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,s=10;
char c;
int main(){
cin>>a>>c>>b;
while(a){
long long s1=a/s;
long long s2=a%s;
if(s1+s2==b){
cout<<s1<<"+"<<s2<<"="<<b;
return 0;
}
s*=10;
}
cout<<"Impossible!";
return 0;
}
奶牛正在试验秘密代码,并设计了一种方法来创建一个无限长的字符串作为其代码的一部分使用。
给定一个字符串,让后面的字符旋转一次(每一次正确的旋转,最后一个字符都会成为新的第一个字符)。也就是说,给定一个初始字符串,之后的每一步都会增加当前字符串的长度。
给定初始字符串和索引,请帮助奶牛计算无限字符串中位置N的字符。
输入
第一行输入一个字符串。该字符串包含最多30个大写字母,并N≤10^18
第二行输入N。请注意,数据可能很大,放进一个标准的32位整数可能不够,所以你可能要使用一个64位的整数类型(例如,在C / C++ 中是 long long)
输出
请输出从初始字符串生成的无限字符串中的位置的字符。
样例输入
COW 8
样例输出
C
提示
样例解释:
COW -> COWWCO -> COWWCOOCOWWC
12 3 4 5 678
#include<bits/stdc++.h>
using namespace std;
char a[1000001];
int main(){
char ch;
long long n,num=0;
while(scanf("%c",&ch),ch!=' ')
a[++num]=ch;
scanf("%lld",&n);
while(num<n){
long long i=num;
while(n>i*2)i*=2;
n-=(i+1);
if(n==0)n=i;
}
printf("%c",a[n]);
return 0;
}
现在很多地方的道路路口都安装了电子警察,即交通违章自动拍照系统。这些系统一般在路口的地下埋设感应线圈,通过传感器判断汽车是否在红灯时通过路面,来控制数码相机自动拍照。在安装这种系统需要挖掘地面,施工麻烦,成本又高。于是有人研究出了同摄像机自动识别车牌并判断违章行为的系统,这样一来,电子警察安装就方便多了,成本也大大降低。请你编程实现其中的一个功能,给出一批某一时间识别后的车牌号码及行进方向,判断该车是否违章,并记录下来。违章的规则设定为:先设置左转、直行、右转依次绿灯通行时间(以秒为单位,只允许一个方向绿灯),先左转绿灯,然后直行绿灯,最后右转绿灯,在其中一个绿灯时,其余两盏灯为红灯状态,假设时间生效在零时整,且给出的数据只限定当天。闯红灯为违章。
输入
第1行有4个整数,以一个空格隔开,依次为左转、直行、右转通行的绿灯持续秒数和识别的车辆数N(1≤N≤10000),后面的N行,表示每辆车的信息,格式为“时间+方向+车牌”,其中时间为6位数字,方向为1个字母(L表示左转,S表示直行,R表示右转),车牌为8个字符,之间没有空格。如081528LZJBB0001,表示车牌号为ZJBB0001的车辆在8时15分28秒左转
输出
违章车辆的车牌号码,每辆车一行,不含空格,按输进去的先后顺序输出。
样例输入
15 30 20 3 000046SZJBB8888 030950LJSAA9999 201509RBJC7777D
样例输出
ZJBB8888 BJC7777D
#include<bits/stdc++.h>
using namespace std;
int le,ri,st,n,ti,h;
char d;
string c;
string a[100000+5];
int main(){
cin>>le>>st>>ri>>n;
for(int i=0;i<n;i++){
cin>>ti>>d>>c;
int m=ti%100,f=(ti/100)%100,s=ti/10000,zm=m+(60*f)+(3600*s),l=zm%(le+ri+st);
if(d=='L'&&(l==0||l>le)){
a[h++]=c;
}
if(d=='S'&&(l<=le||l>le+st)){
a[h++]=c;
}
if(d=='R'&&l<=le+st&&l>=1){
a[h++]=c;
}
}
for(int i=0;i<h;i++){
cout<<a[i]<<endl;
}
return 0;
}