C++: 字符串详解及例题解析

目录

一、字符与整数间的桥梁——ASCII码

二、字符数组

字符数组的输入输出

遍历字符数组

三、标准库类型string

四、例题解析

例1:去掉多余的空格

例2:单词替换

例3: 字符串中最长的连续出现的字符

例4:最长单词

例5:倒排单词

例6: 字符串移位包含问题

例7:字符串乘方

例8:字符串最大跨距


一、字符与整数间的桥梁——ASCII码

每个常用字符都对应一个128--127的数字,二者可相互转化;

常用ASCLL码:A是65,a是97,后面在此基础上推算;

字符可以参与运算,运算时会将其当作整数。

#include<iostream>
using namespace std;
int main(){
    //字符转ASCLL码
    char s='a';
    cout<<(int)s<<endl;

    //ASCLL码转字符
    int a=66;
    cout<<(char)a<<endl;

    return 0;
}

二、字符数组

所谓的字符串就是字符数组加上结束符“/0”。可以用字符串来初始化字符数组,但是要注意每个字符串结尾会含有一个“/0”,因此字符数组的长度至少要比字符串多1。

#include<iostream>
using namespace std;
int main(){

    char s1[]={'a','b','c'};
    char s2[]="abc";         //自动添加“/0”
    char s3[3]="abc";        //错误:没有空间存放“/0”
    
    return 0;
}

字符数组的输入输出

#include<iostream>
using namespace std;
int main(){

    char s[100];
    
    cin>>s;     //输入字符串时,遇到空格或者回车就会停止
    cout<<s;    //输出字符串时,遇到空格或者回车不会停止
    getline(cin,s)  //可读入带空格的字符串

    return 0;
}

遍历字符数组

#include<iostream>
#include<string.h>
using namespace std;
int main(){

    char a[] = "hello world!";
    for(int i=0; i<strlen(a); i++)  cout<<a[i]<<endl;
   
    return 0;
}

三、标准库类型string

可变长的字符序列,比字符数组更好用,但要注意:用string定义字符串时,需要引用头文件:#include<string>。

同时,string支持> < = <= == !=等所有比较操作,按字典序进行排序。

string也可直接相加:

#include<iostream>
#include<string>
using namespace std;
int main(){
    
    string s1="abc";
    string s2="def";
    string s3=s1+s2;

    cout<<s3;
}

  可以把string对象当作字符数组来处理

#include<iostream>
#include<string>
using namespace std;
int main(){

    string s="hello world";
    for(int i=0;i<s.size();i++)
    {
        cout<<s[i]<<endl;
    }

    return 0;
}

四、例题解析

例1:去掉多余的空格

输入一个字符串,字符串中可能包含多个连续的空格,请将多余的空格去掉,只留下一个空格。

输入格式

共一行,包含一个字符串。

输出格式

输出去掉多余空格后的字符串,占一行。

输入样例:

Hello      world.This is    c language.

输出样例:

Hello world.This is c language.
#include<iostream>
#include<string>
using namespace std;
int main(){
     
    string s;
    getline(cin,s);

    string r;   //r为最终输入答案

    for(int i=0;i<s.size();i++)
    {
        if(s[i]!=' ') r+=s[i];
        else
        {
           r+=' ';       
           int j=i;  //双指针常用思路!!
           while(j<s.size() && s[j]==' ') j++;
           i=j-1;
        }
     }

     cout<<r<<endl;

     return 0;
}

例2:单词替换

输入一个字符串,以回车结束(字符串长度不超过100)。

该字符串由若干个单词组成,单词之间用一个空格隔开,所有单词区分大小写。

现需要将其中的某个单词替换成另一个单词,并输出替换之后的字符串。

输入格式

输入共 3行。

第 11行是包含多个单词的字符串 s;

第 2 行是待替换的单词 a(长度不超过 100);

第 3 行是 a 将被替换的单词 b(长度不超过100)。

输出格式

共一行,输出将 s 中所有单词 a 替换成 b 之后的字符串。

输入样例

You want someone to help you
You
I

输出样例

I want someone to help you
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main(){
   
    string s,a,b;
    getline(cin,s);
    cin>>a>>b;

    stringstream ssin(s);  //把字符串初始化,通过ssin读取任意信息,
    string str;
    while(ssin>>str)  //初始化后ssin作用相当于cin
    {
        if(str==a) cout<<b<<' ';
        else cout<<str<<' ';
    }

    return 0;
}

例3: 字符串中最长的连续出现的字符

求一个字符串中最长的连续出现的字符,输出该字符及其出现次数,字符串中无空白字符(空格、回车和 tab),如果这样的字符不止一个,则输出第一个。

输入格式

第一行输入整数 N,表示测试数据的组数。

每组数据占一行,包含一个不含空白字符的字符串,字符串长度不超过 200。

输出格式

共一行,输出最长的连续出现的字符及其出现次数,中间用空格隔开。

输入样例:

2
aaaaabbbbbcccccccdddddddddd
abcdefghigk

输出样例:

d 10
a 1
#include<iostream>
using namespace std;
int main(){
 
    int n;
    cin>>n;

    while(n--)
    {
       string str;
       cin>>str;

       int cnt = 0;
       char c;    //最大出现次数对应的字符
 
       for(int i=0; i<str.size();i++)
       {
          int j=i;
          while(j<str.size() && str[j]==str[i]) j++;  //又一次双指针算法
          if(j-1 > cnt)  cnt=j-i, c=str[i];
          i=j-1;
       }

       cout<< c <<' '<< cnt <<endl;
    }

    return 0;
}

 例4:最长单词

一个以  . 结尾的简单英文句子,单词之间用空格分隔,没有缩写形式和其它特殊形式,求句子中的最长单词。

输入格式

输入一行字符串,表示这个简单英文句子,长度不超过 500。

输出格式

该句子中最长的单词。如果多于一个,则输出第一个。

输入样例:

I am a student of Peking University.

输出样例:

University
#include<iostream>
#include<string>
using namespace std;
int main(){

    string str,res; //设res为最长单词
    
    while(cin>>str)
    {
       if(str.back()=='.') str.pop_back();  //pop_back可去掉最后一个字符
       if(str.size() > res.size()) res=str;
    }

    cout<< res <<endl;
    return 0;
}

例5:倒排单词

编写程序,读入一行英文(只包含字母和空格,单词间以单个空格分隔),将所有单词的顺序倒排并输出,依然以单个空格分隔。

输入格式

输入为一个字符串(字符串长度至多为100)。

输出格式

输出为按要求排序后的字符串。

输入样例

I am a student

输出样例:

student a am I
#include<iostream>
using namespace std;
int main(){
    
    string str[100];
    
    int n=0;
    while(cin>>str[n]) n++;
    
    for(int i=n-1;i>=0;i--) cout<<str[i]<<' ';
    cout<<endl;
    
    return 0;
}

例6: 字符串移位包含问题

对于一个字符串来说,定义一次循环移位操作为:将字符串的第一个字符移动到末尾形成新的字符串。

给定两个字符串 s1s1 和 s2s2,要求判定其中一个字符串是否是另一字符串通过若干次循环移位后的新字符串的子串

例如 CDAA 是由 AABCD 两次移位后产生的新串 BCDAA 的子串,而 ABCD 与 ACBD 则不能通过多次移位来得到其中一个字符串是新串的子串。

输入格式

共一行,包含两个字符串,中间由单个空格隔开。

字符串只包含字母和数字,长度不超过 30。

输出格式

如果一个字符串是另一字符串通过若干次循环移位产生的新串的子串,则输出 true,否则输出 false

输入样例:

AABCD CDAA

输出样例:

true
#include<iostream>
#include<algorithm>  //含有swap函数
using namespace std;
int main(){
    
    string a,b;
    cin>>a>>b;
    
    if(a.size()<b.size())  swap(a,b);
    
    for(int i=0; i<a.size(); i++)
    {
        a=a.substr(1)+ a[0];    //先通过substr把a的第0个位置去掉,再在后面加上a[0]
        for(int j=0; j+b.size()<=a.size(); j++)   //接下来枚举b是否是a的子串
        {
            for(int k=0; k<b.size(); k++)   //用k来遍历是不是所有的位置都相等
            {
                if(a[j+k]!=b[k])
                {
                    break;
                }
                if(k == b.size()) 
                {
                    puts("true");
                    return 0;
                }
            }
        }
    }
    
    puts("false");
    return 0;
}

例7:字符串乘方

给定两个字符串 aa 和 bb,我们定义 a×ba×b 为他们的连接。

例如,如果 a=abc 而 b=def, 则 a×b=abcdef

如果我们将连接考虑成乘法,一个非负整数的乘方将用一种通常的方式定义:a的0次方=``(空字符串),a的(n+1)次方 = a×(a的n次方)。

输入格式

输入包含多组测试样例,每组测试样例占一行。

每组样例包含一个字符串 s,s 的长度不超过100,且不包含空格。

最后的测试样例后面将是一个点号作为一行。

输出格式

对于每一个 s,你需要输出最大的 n,使得存在一个字符串 a,让 s = a的n次方。

输入样例:

abcd
aaaa
ababab
.

输出样例:

1
4
3
#include<iostream>
using namespace std;
int main(){
    
    string str;
    
    while(cin>>str,str!=".")
    {
        int len=str.size();
        
        for(int n=len; n>=0; n--) //枚举一下n
        {
            if(len % n==0)
            {
                int m=len/n;
                string s = str.substr(0,m);  //s是从0-m的一段字符
                string r;    //r是拼接字符串
                for(int i=0;i<n;i++)
                {
                    r+=s; 
                }
                if(r==str)  //判断拼接的字符串与原字符串是否相等
                {
                    cout<<n<<endl;
                    break;
                }
            }
        }
    }
    
    return 0;
}

例8:字符串最大跨距

有三个字符串 S,S1,S2,其中,S 长度不超过300,S1 和 S2 的长度不超过 10。

现在,我们想要检测 S1 和 S2是否同时在 SS 中出现,且 S1位于 S2 的左边,并在 S 中互不交叉(即,S1 的右边界点在 S2的左边界点的左侧)。

计算满足上述条件的最大跨距(即,最大间隔距离:最右边的 S2 的起始点与最左边的 S1 的终止点之间的字符数目)。

如果没有满足条件的 S1,S2 存在,则输出 −1。

例如,S= abcd123ab888efghij45ef67kl, S1= ab, S2= ef,其中,S1 在 S 中出现了 2 次,S2 也在 S 中出现了 2次,最大跨距为:18。

输入格式

输入共一行,包含三个字符串 S,S1,S2,字符串之间用逗号隔开。

数据保证三个字符串中不含空格和逗号。

输出格式

输出一个整数,表示最大跨距。

如果没有满足条件的 S1和 S2 存在,则输出 −1。

输入样例:

abcd123ab888efghij45ef67kl,ab,ef

输出样例:

18
#include<iostream>
using namespace std;
int main(){
    
  string s,s1,s2;
     
  char c;
  while(cin>>c, c!=',') s+=c;
  while(cin>>c, c!=',') s1+=c;
  while(cin>>c) s2+=c;
    
  if(s.size()<s1.size() || s.size()<s2.size())  puts("-1");
    
  else
  {
    //先找最左边s1的位置
    int l=0;  //用l表示s1的起点
    while(l + s1.size() <= s.size())
    {
        int k;  //判断是否和s1相等
        while(k<s1.size())
        {
            if(s[l+k] != s1[k])  break;
            k++;
        }
        
        if(k==s1.size()) break;  //说明和s1匹配
        l++;
    }
    
    //同理,再找最右边s2的位置
    int r=s.size() - s2.size();  //用r表示s2的起点
    while(r>=0)
    {
        int k=0;
        while(k < s2.size())
        {
            if(s[r+k] != s2[k]) break;
            k++;
        }
        
        if(k==s2.size()) break;
        r--;
    }
    
    l+=s1.size()-1;
    
    if(l>=r) puts("-1");
    else
    {
        cout<<r-l-1;
    }
    
  }
  
  return 0;
}

  • 14
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值