华师一附中OI组

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3037|回复: 4
打印 上一主题 下一主题

字符和字符串专题

[复制链接]

61

主题

147

帖子

563

积分

超级版主

Rank: 8Rank: 8

积分
563
跳转到指定楼层
楼主
发表于 2017-10-18 10:00:51 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
除了数值计算之外,计算机也可以处理ABCD1234这样的字符和"diggersun"这样的字符串。我们生活中人处理字符串的方式和计算机中的处理方式有点不一样,所以很多同学碰到字符串处理问题的时候都会沿用生活中的方式,但是这样并不是正确或者高效的,比如有人会string s='1'+'2';for(string i="1";i<="50";i++),等等,这些都是不对的。这栋楼专门来训练字符串的处理技巧。
首先介绍一个字符的概念
字符char是c++里面的一个基本数据类型,用来表示ABCD1234等单个的数字字母符号等,每个字符虽然显示的是ABCD1234。但是在计算机里面是一个数字,比如字符A,看到的是A,但在计算机里存放的是数值是65,(详情请看ASCII表)
char ch  定义一个字符ch
int i  定义一个整数i
ch='A'  赋值
cout<<ch  显示A
cout<<int (ch)  显示65
i=ch 可以和整数相互赋值
cout<<i 显示65
cout<<char(i) 显示A
if (ch==i) cout <<"YES" 显示YES 因为65就是A A就是65,只是表现形式不一样,有点像人的姓名和身份证(假设是整数)一样。
字符的读入一般用cin和cout。cin>>ch表示读入单个个字符ch。重点: ASCII表里面的字符是有顺序的,我们要记住
'0'=48 '9'=57, 中间是连续的
'A'=65,'Z'=90,中间是连续的
'a'=97,'z'=112,中间是连续的利用这个性质我们可以进行字符的大小写转换,数字的字符对应等运算:
比如:'9'-'3'=57-51=6
'A'='a'-32;
'B'='b'-32;
'Z'='A'+26-1;

下面在说说字符串,就是一串字符,基本可以认为像羊肉串一样用根棍子把几块羊肉(字符)串起来。所以它和字符是完全不一样的,哪怕只有一个字符的字符串,也还有一根签子,不等于一个字符。
string s  定义一个字符串类型的变量s,这里我们可以完全忘记掉c语言中的那些字符数组等概念,他们基本上过时了。
cin>>s 读入一个字符串,读到空格或回车结束。所以读到的字符s里面不会有空格。
getline(cin.s) 读入一个字符串,读到回车结束,这样就可以读含有空格的字符串,比如外国人的名字。
int l=s.size()  求s串的长度
char c=s[x]  取出s的第x位,记住:和数组一样,首位是s[0]
string s2=s+s 两个字符串相加,就是将第二个接在第一个的后面
int p=s.find(s1,i) 从第i位开始查找s串中第一次出现s1串的位置,大多数情况下简写为s.find(s1) 表示从首位开始查找,若没有找到,返回-1
string a = s.substr(x,y);     获得字符串s中从第x位开始的长度为y的字符串
s.erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
s.insert(p,a);——在s串的p位置插入字符串a

字符串的大小比较:按字典序比较大小,假设两个字符串s和t,先比较第一个字符的大小,若s[0]>t[0],则s>t,若s[0]<t[0],则s<t,若s[0]==t[0],则继续比较下一位,若某一个字符没有了则比较小。比如"123"<"223"  "123"=="123" "123"<"1234"

忘记那些C里面的字符串函数和字符数组函数吧

简单训练题:

1、P5015 标题统计  http://hsyit.cn/forum.php?mod=viewthread&tid=69190
2、P1200 [USACO1.1]你的飞碟在这儿Your Ride Is He…  http://hsyit.cn/forum.php?mod=viewthread&tid=35954
3、P1781 宇宙总统  http://hsyit.cn/forum.php?mod=viewthread&tid=36232
4、P1125 笨小猴 http://hsyit.cn/forum.php?mod=viewthread&tid=36005
5、P1055 ISBN号码  http://hsyit.cn/forum.php?mod=viewthread&tid=35792
6、P1042 乒乓球 http://hsyit.cn/forum.php?mod=viewthread&tid=35814
7、P1914 小书童——密码  http://www.hsyit.cn/forum.php?mod=viewthread&tid=35838&extra=
8、P2670 扫雷游戏  http://hsyit.cn/forum.php?mod=viewthread&tid=35817
9、P1598 垂直柱状图 http://www.hsyit.cn/forum.php?mo ... e=1&extra=#pid36815


复杂一点的字符串
1、P1071 潜伏者 http://hsyit.cn/forum.php?mod=viewthread&tid=36132
2、P1308 统计单词数  http://hsyit.cn/forum.php?mod=viewthread&tid=36119
3、P1246 编码  http://hsyit.cn/forum.php?mod=viewthread&tid=36122
4、P2037 电话号码 http://hsyit.cn/forum.php?mod=viewthread&tid=36215
5、P1012 拼数  http://hsyit.cn/forum.php?mod=viewthread&tid=35806
6、P1603 斯诺登的密码   http://hsyit.cn/forum.php?mod=viewthread&tid=36265












回复

使用道具 举报

738

主题

1485

帖子

5422

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
5422
5#
发表于 2019-3-16 17:33:37 | 只看该作者
顶上去
回复

使用道具 举报

61

主题

147

帖子

563

积分

超级版主

Rank: 8Rank: 8

积分
563
地板
 楼主| 发表于 2017-10-18 10:19:19 | 只看该作者
第三题 笨小猴,也是字符和数字的对应,然后统计出现的次数。注意,0次不算的。定义数组,a,其实a0表示a出现的次数,a1表示b,a25表示z,那么a对应着0,有个转换算式,和上面的一样。
然后把大于1的次数的最小值和最大值都求出来,相减,判断质数就是。注意,有个小坑:最小的次数不是0,而是1。
传送门
http://hsyit.cn/forum.php?mod=viewthread&tid=36005
回复 支持 反对

使用道具 举报

61

主题

147

帖子

563

积分

超级版主

Rank: 8Rank: 8

积分
563
板凳
 楼主| 发表于 2017-10-18 10:13:01 | 只看该作者
第二题  ISBN 2008普及组第一题  洛谷P1055
给出一个字符串,取出其中某些位,进行运算,比上一个复杂一点,不是连续位置上的字符。
考点:字符和数字的对应关系,基本方法:硬的计算每一位对应的数字,然后处理余数
  1. #include <iostream>
  2. using namespace std;
  3. string s,t;
  4. int i,j;
  5. char ch;
  6. int main()
  7. {
  8.     cin>>s;
  9.     j=0;
  10.     j=j+(s[0]-'0')*1;
  11.     j=j+(s[2]-'0')*2;
  12.     j=j+(s[3]-'0')*3;
  13.     j=j+(s[4]-'0')*4;
  14.     j=j+(s[6]-'0')*5;
  15.     j=j+(s[7]-'0')*6;
  16.     j=j+(s[8]-'0')*7;
  17.     j=j+(s[9]-'0')*8;
  18.     j=j+(s[10]-'0')*9;
  19.     j=j%11;
  20.     if (j<=9) ch=j+'0';else ch='X';

  21.     if (s[12]==ch) cout<<"Right";else
  22.     {cout<<s.substr(0,12);cout<<ch;}

  23. }
复制代码


本体还有就一种技巧性的方法,非连续位置的处理。
  1. #include<iostream>
  2. using namespace std;
  3. string s,t;
  4. int i,sum;
  5. int h[9]={0,2,3,4,6,7,8,9,10}; ///这个hash表可以将不连续的映射成连续
  6. int main()
  7. {
  8.     cin>>s;
  9.     for (i=0;i<=8;i++)
  10.         sum+=(s[h[i]]-'0')*(i+1);
  11.     sum%=11;t=s;
  12.     if (sum==10) t[t.size()-1]='X';else t[t.size()-1]=sum+'0';
  13.     if (t==s) cout<<"Right";else cout<<t;
  14.     return 0;
  15. }
复制代码




回复 支持 反对

使用道具 举报

61

主题

147

帖子

563

积分

超级版主

Rank: 8Rank: 8

积分
563
沙发
 楼主| 发表于 2017-10-18 10:11:43 | 只看该作者
第一题 USACO 你的飞碟在这儿Your Ride Is He…  洛谷P1200很简单的字符串题目,每一位上的字符对应一个数字,将这些数字乘起来,看两组数据是否同余。
考点:字符串的读入,求长度,取每一位的字符,字符和数字的对应关系。
此题的读入用cin就行了,因为不含有空格,cin读入的通用性还是好些。求长度就用size()函数,取字符就用s(i)
字符A对应着1,B对应着2,就用x=ch-‘A’+1这种通用方法。

参考程序:
  1. #include<iostream>
  2. using namespace std;
  3. string s1,s2;
  4. int t1,t2,x,i;
  5. int main()
  6. {
  7.     cin>>s1>>s2;
  8.     t1=1;
  9.     for (i=0; i<=s1.size()-1; i++)
  10.     {
  11.         x=s1[i]-'A'+1;
  12.         t1=t1*x;
  13.     }

  14.     t2=1;
  15.     for (i=0; i<=s2.size()-1; i++)
  16.     {
  17.         x=s2[i]-'A'+1;
  18.         t2=t2*x;
  19.     }

  20.     if ((t1%47)==(t2%47)) cout<<"GO";
  21.     else cout<<"STAY";
  22.     return 0;
  23. }
复制代码



此题比较简单,只有6位数,就没有每次乘的时候取余,而是一起乘完后一起处理,注意枚举每一位的技术和转换为数字的技巧。




回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|服务支持:DZ动力|华师一附中OI组  

GMT+8, 2024-12-26 01:53 , Processed in 0.223656 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表