冲刺蓝桥杯第三章字符串

ASCII码值、字母大小写转换、‘0’~‘9’

//数字转字符:'A'(65)'a'(97)'0'(48)
char A=char(65);
char a=char(97);
char c='a'+2;//'c'='a'+2
char seven='0'+7;//'7'='0'+7;
//字符转数字
int a='a';//a:97
int A='A';//A:65
int t='t'-'a';//可以计算字母间的差值
int seven='7'-'0';

子典序

字典序就是以ASCII码排序。
比如两个字符串 abcd 和 abdd 比较大小。 从第一个字符开始逐位比较,第一个字符不相等,谁的ASCII码值小谁的字典序就小。若第一个相等,继续逐位比较后续字符。比较到字母c < 字母d,所以第一个字符串abcd 字典序较小。
再比如 hist 和 history 比较大小。若逐位比较都相等,但其中一个没有后续的字符了,则较短的串 hist 字典序较小。
使用 sort() 可以对字符串进行字典序排序,字符按ASCII码值由小到大排列。

题目描述

有N个长为工的字符串、S1,S2,…拓拓将以某种顺序连接所有字符串,拼接成一个长字符串。在拼接出的所有长字符串中,找到字典序最小的一个。

输入格式

第一行两个正整数 N 和工.
接下来 N 行每行一个字符串 S1,S2,.SN

输出格式

输出一行,输出拼接出的字典序最小的字符串

样例

输入数据

3 3
dxx
axx
cxx

输出数据

axxcxxdxx

数据范围

1<=N,L<=100
对于每个i(1≤i≤N),Si的长度等于L。
对于每个i(1≤i≤N),Si全部由小写字母组成。

code:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    int n,l;
    cin>>n>>l;
    string s[100];
    for(int i=0;i<n;i++) cin>>s[i];
    sort(s,s+n);
    for(int i=0;i<n;i++) cout<<s[i];
    cout<<endl;
    return 0;
}

排列字母

小蓝要把一个字符串中的字母按其在字母表中的顺序排列。 例如,LANQIAO 排列后为 AAILNOQ。又如,GOODGOODSTUDYDAYDAYUP 排列后为AADDDDDGGOOOOPSTUUYYY 请问对于以下字符串,排列之后字符串是什么?WHERETHEREISAWILLTHEREISAWAY
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个由大写字母组成的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。

code:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
    string s;
    cin>>s;
    sort(s.begin(),s.end());
    cout<<s<<endl;
    return 0;
}

字符串常用函数和reverse

#include<iostream>
#include<string>
using namespace std;
string s;
int main(){
    s.size();//返回字符串的长度
    s.length();//返回字符串的长度
    s.empty();//判断队列是否为空,为空返回1,否则返回0
    s[n];//取s中第n+1个字符
    reverse(s.begin(),s.end());//翻转字符串
    //查找
    s.find("ab");//返回字符串ab在s的位置
    s.find("ab",2);//在s[2]~s[n-1]的范围内查找并返回字符串ab在s的位置
    s.rfind("ab",2);//在s[0]~s[2]的范围内查找并返回字符串ab在s的位置
    //子串
    s.substr(3);//返回s[3]及其以后的子串
    s.substr(2,4);//返回s[2]~s[2+(4-1)]的子串,即从s[2]开始往后4个字符组成的字符串
    s.substring(5,10);//返回s[5]~s[9]的子串(不包含结尾)
    //插入
    s.insert(2,"ab");//从s[2]位置开始添加字符串"ab",并返回形成的新字符串
    s.insert(2,"abcd",3);//从s[2]位置开始添加字符串“abcd”的前3个字符,并返回形成的新字符串
    s.insert(2,"abcd",1,3);//从s[2]位置开始添加字符串“abcd”的前s[2]~s[2+(3-1)]个字符,并返回新形成的字符串
    //删除
    s.erase(3);//删除s[3]以及以后的字符,并返回新形成的字符串
    s.erase(3,5);//删除s[3]开始的5个字符,并返回新字符串
    //替换
    s.replace(2,4,"ab");//返回把s[2]~s[2+(4-1)]的内容替换为“ab”后的新字符串
    s.replace(2,4,"abcd",3);//返回把s[2]~s[2+(4-1)]的内容替换为“abcd”的前3个字符后的新字符串
    //加串
    s=s+"abc";
    s.push_back('a');//在s的尾部添加字符‘a’
    s.append("abc");//在s的尾部添加字符串“abc”
    //大小写转换
    //法一:
    tolower(s[i])//转换为小写
    toupper(s[i]);//转换为大写
    //法二:
    //通过stl的 transform 算法配合 tolower 和 toupper 实现。
    //有4个参数,前2个指定要转换的容器的起止范围,第3个参数是结果存放容器的起始位置,第4个参数是一元运算。
    string s;
    transform(s.begin(),s.end(),s.begin(), : tolower); //转换小写
    transform(s.begin(),s.end(),s.begin(), : toupper); //转换大写        
} 

string与C语言字符串(C-string)的区别

string是C++的一个类,专门实现字符串的相关操作。具有丰富的操作方法,数据类型为 string ,字符串结尾没有 \0 字符
C-string是C语言中的字符串,用char数组实现,类型为 const char * ,字符串结尾以 \0 结尾
一般来说string向char数组转换会出现一些问题,所以为了能够实现转换,string有一个方法 c_str() 实现string向char数组的转换。

string s = "xing ma qi";
char s2[] = s.c_str();

字符串编号

题目描述:

小明发明了一种给由全大写字母组成的字符串编码的方法。对于每一个大写字母,小明将它转换成它在 26 个英文字母中序号,即 A→1,B→2,…Z→26。这样一个字符串就能被转成一个数字序列:比如 ABCXYZ→123242526。现在给定一个转换后的数字序列,小明想还原出原本的字符串。当然这样的还原有可能存在多个符合条件的字符串。小明希望找出其中字典序最大的字符串。

输入格式

输入一行一个数字序列。

输出格式

输出一行一个只包含大写字母的字符串,代表答案。

样例

输入数据

123242526

输出数据

LCXYZ

数据范围

对于 20% 的评测用例,输入的长度不超过20。对于所有评测用例,输入的长度不超过200000。

code:

#include<iostream>
#include<string>
using namespace std;
int main(){
    string s;
    cin>>s;
    int len=s.size();
    for(int i=0;i<len;i++){
        int a=s[i]-'0',c=stoi(s.substr(i,2));
        if(c>26){
            cout<<(char)(a+'A'-1);
        }
        else{
            i++;
            cout<<(char)(c+'A'-1);
        }
    }
    return 0;
}

子串

题目描述

这是一道模板题。 给定一个字符串 A 和一个字符串 B,求 B 在 A 中的出现次数。A 和 B 中的字符均为英语大写字母或小写字母。 A 中不同位置出现的 B 可重叠。

输入格式

输入共两行,分别是字符串 A 和字符串 B。

输出格式

输出一个整数,表示 B 在 A 中的出现次数。

样例

输入数据

zyzyzyz
zyz

输出数据

3

数据范围

对于 100% 的测试数据满足: A,B 的长度 <=10^6 , A,B 仅包含大小写字母。

code:

#include<iostream>
#include<string>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    string a,b;
    cin>>a>>b;
    int s=0;
    int t=a.find(b);
    while(t!=string::npos){
        s++;
        t=a.find(b,t+1);
    }
    cout<<s<<endl;
    return 0;
}

删除字符

题目描述

编写一个程序,先输入一个字符串 str(长度不超过20),再输入单独的一个字符 ch,然后程序会把字符串 str 当中出现的所有的 ch 字符都删掉,从而得到一个新的字符串 str2,然后把这个字符串打印出来。

输入格式

输入有两行,第一行是一个字符串(内部可能含空格),第二行是一个字符。

输出格式

经过处理以后的字符串。

样例

输入数据

123-45-678
-

输出数据

12345678

code:

#include<iostream>
#include<string>
using namespace std;
int main(){
    string str;
    char ch;
    getline(cin,str);
    cin>>ch;//ch为字符不可以用getline来读入,getline与cin混用错误原因是cin 会剩一个换行符, getline 会把这个换行符读进来导致直接结束字符串读入。因此可以先使用getline来读入后用cin来读入
    int p=str.find(ch);
    while(p!=string::npos){
        str.erase(p,1);
        p=str.find(ch);
    }
    cout<<str<<endl;
    return 0;
}

替换单词

题目背景

最近,谷歌公司做出了一项决定,由于black list(黑名单)这个词语不好听,所以需要将它们修改成block list(屏蔽名单)。

题目描述

给定一个仅仅由小写字母组成的字符串s,请将其中所有的black全部替换成block。

输入格式

单个字符串:表示需要替换的字符串s。

输出格式

单个字符串:表示将black替换成block后的字符串。

样例

输入数据

ablacklistblackmatter

输出数据

ablocklistblockmatter

数据范围

设字符串的长度为|s|,则
对于50%的数据,1<|s|<200;
对于100%的数据,1<|s|<200000.

code:

#include<iostream>
#include<string>
using namespace std;
int main(){
    string s,w,t;
    cin>>s;
    w="black";
    t="block";
    int p=s.find(w);
    while(p!=string::npos){
        s.replace(p,5,t);
        p=s.find(w);
    }
    cout<<s<<endl;
    return 0;
}

stringstream

头文件:sstream
stringstream主要是用在字符串分割,可以先用clear()以及str()将字符串读入并进行分割,再用>>把内容输出。

#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main(){
    string s;
    stringstream ss;
    int a,b,c;
    getline(cin,s);
    ss.clear();
    ss.str(s);
    ss>>a>>b>>c;
    return 0;
}

stringstream详解:

stringstream是C++ 提供的专门用于处理字符串的输入输出流类。

stringstream的用法:

1、构造函数:
stringstream 的构造函数有很多,这里列举最为常用的两个构造函数:

<1>、创建一个对象,向对象输入字符串:

    // 创建一个 string类  对象 s
	string s("hello stringstream");
	// 创建一个 stringstraeam类 对象 ss
	stringstream ss;
	// 向对象输入字符串 : "<<" 表示向一个对象中输入
	ss << s;
	cout << ss.str() << endl;

<2>、在创建对象的时候使用字符串初始化:

    // 创建一个 stringstraeam类 对象 ss
	stringstream ss("hello stringstream");
	cout << ss.str() << endl;

两种方式都可以创建对象,但创建后的对象用法不一样,详见后面的示例。
2、输出字符串
stringstream 可以将存储于内部的字符串输出,需要调用 str() 函数,不可直接输出:

std::cout << ss.str() << std::endl;
// std::cout << ss << std::endl; 		// 错误不可直接输出

注意:cout << ss << endl; 是错误的,不可以直接输出
3、两种构造函数带来的不同
上面阐述了两种构造函数,利用不同的构造函数创建对象,对象具体的操作也不同:
<1>、 第一种构造方式

#include <iostream>
#include <sstream>
using namespace std;
 
int main()
{
    stringstream ss1;
    ss1 << "fre";
    ss1 << "gre";
    cout << ss1.str() << endl;
    
    return 0;
}
 
/*
输出:
fregre
*/

可以发现,两个字符串直接拼接在了一起
<2>、第二种构造方式

#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    string str("asd");
    // 第二种构造
    stringstream ss2(str);
    cout << ss2.str() << endl;
    // 第一种构造
    ss2 << "r";
    cout << ss2.str() << endl;
    ss2 << "13";
    cout << ss2.str() << endl;
    ss2 << "hy";
    cout << ss2.str() << endl;
    return 0;
}
/*
输出:
asd
rsd
r13
r13hy
*/

可以发现,利用第一种构造函数创建对象时,输入字符串后直接进行字符串拼接,而第二种构造方式,在进行字符串拼接时,首先把原本的字符串覆盖掉,之后再进行拼接。
<3>、 如果不想原来的字符串被覆盖,则需要换一种构造方式,如下:

#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    ostringstream ss("1 2 3 4 ", std::ios_base::ate);	// append 方式追加
    cout << ss.str() << endl;
    ss << "5 3 4";
    cout << ss.str() << endl;
    return 0;
}
/*
输出:
1 2 3 4 
1 2 3 4 5 3 4
*/

4、修改、清空 stringstream 内容
stringstream 的内容可以通过 str() 函数进行修改、清空:

#include <iostream>
#include <sstream>
using namespace std;
int main()
{
    stringstream ss("hello string");
    cout << ss.str() << endl;
    // 修改内容
    ss.str("hello stringstream");
    cout << ss.str() << endl;
    // 清空内容
    ss.str("");
    cout << ss.str() << endl;
    return 0;
}
/*
输出:
fghewoo
123456
*/

srtingstream练习

题目描述

输入的第一行有一个数字 N 代表接下來有 N 行数字,每一行有若干个的整数(最多 20 个,每行最多 200个字符),请你输出每一行数字的和。

输入格式

第一行一个整数 N。
接下来输入 N 行,每行若干个整数。

输出格式

输出N行,每行一个整数表示。

样例

输入数据

3
1 2 3
20 17 23 54 77 60
111 222 333 444 555 666 777 888 999

输出数据

6
251
4995

code:

#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main(){
    string s;
    stringstream ss;
    int n,sum,i,a;
    cin>>n;
    getline(cin,s);
    for(int i=1;i<=n;i++){
        getline(cin,s);
        ss.clear();
        ss.str(s);
        sum=0;
        while(1){
            ss>>a;
            if(ss.fail()) break;
            sum+=a;
        }
        cout<<sum<<endl;
    }
    return 0;
}

sprintf

sprintf是一个比较冷门的函数,可以直接把相应的整数拼接组合成我们规定的格式。

sprintf详解

char str[80];
sprintf(str, "%c", 'A'); // 输出字符 A
sprintf(str, "%d", 123); // 输出十进制整数 123
sprintf(str, "%x", 255); // 输出十六进制整数 ff
sprintf(str, "%f", 3.14); // 输出浮点数 3.140000
sprintf(str, "%s", "Hello"); // 输出字符串 Hello
sprintf(str, "%10d", 123); // 输出宽度为 10 的十进制整数,右对齐,空位用空格填充:       123
sprintf(str, "%-10d", 123); // 输出宽度为 10 的十进制整数,左对齐,空位用空格填充:123       
sprintf(str, "%010d", 123); // 输出宽度为 10 的十进制整数,右对齐,空位用 0 填充:0000000123
sprintf(str, "%+d", 123); // 输出带正负号的十进制整数:+123
sprintf(str, "%.3d", 123); // 输出至少 3 位的十进制整数,不足则用 0 填充:123
sprintf(str, "%.3d", 12); // 输出至少 3 位的十进制整数,不足则用 0 填充:012
sprintf(str, "%.3f", 3.14); // 输出保留 3 位小数的浮点数:3.140
sprintf(str, "%.3s", "Hello"); // 输出最多 3 个字符的字符串:Hel
sprintf(str, "%ld", 123456789L); // 输出长整型数:123456789
sprintf(str, "%lf", 3.1415926535897932384626433832795L); // 输出长双精度型数:3.141593

sprintf练习

顺子日期

小明特别喜欢顺子。顺子指的就是连续的三个数字:123、456 等。顺子日期指的就是在日期的 уyyymmdd 表示法中,存在任意连续的三位数是一个顺子的日期。例如 20220123 就是一个顺子日期,因为它出现了一个顺子:123; 而 20221023 则不是一个顺子日期,它一个顺子也没有。小明想知道在整个 2022 年份中,一共有多少个顺子日期。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

code:

#include<iostream>
char ch[15];
using namespace std;
int main(){
    int cnt=0,flag=0,ans=0;
    for(int year=2022;year<=2022;year++)
    for(int month=1;month<=12;month++)
    for(int day=1;day<=31;day++){
        if(month==1||month==3||month==5||month==7||month==8||month==10||month==12);
        else if(month==2){
            if(year%4==0&&year%100!=0||year%400==0){
                if(day>29) break;
            }
            else{
                if(day>28) break;
            }
        }
        else{
            if(day>30) break;
        }
        sprintf(ch+1,"%d%02d%02d",year,month,day);//转换格式
        for(int k=4;k+2<=8;k++){//k+2<=8处理边界
            if(ch[k+2]-ch[k+1]==1&&ch[k+1]-ch[k]==1){
                puts(ch+1);
                ans++;
                break;
            }
        }
    }
    cout<<ans;
    return 0;
}

回文日期

题目描述

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2 日。因为如果将这个日期按“yyyymmdd” 的格式写成一个 8 位数是 20200202, 恰好是一个回文数。我们称这样的日期是回文日期。有人表示20200202是“千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202即 2021 年 12 月 2 日。也有人表示20200202并不仅仅是一个回文日期,还是一个ABABBABA型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个ABABBABA型的回文日期:21211212 即 2121 年 12 月 12 日。算不上“千年一遇”,顶多算“千年两遇”。给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个ABABBABA型的回文日期各是哪一天。

输入格式

输入包含一个八位整数 N,表示日期。

输出格式

输出两行,每行 1 个八位数。
第一行表示下一个回文日期,第二行表示下一个ABABBABA型的回文日期。

样例

输入数据

20200202

输出数据

20211202
21211212

数据范围

对于所有评测用例,10000101≤N≤89991231,保证 N 是一个合法日期的 8 位数表示。

code:

#include<iostream>
#include<string>
using namespace std;
int n;
char ch[15];
int flag=0,flag1=0;
bool check1(string s){
    for(int i=0,j=7;i<j;i++,j--){
        if(s[i]!=s[j]) return false;
    }
    return true;
}
bool check2(string s){
    if(check1(s)){
        if(s[0]!=s[2]||s[1]!=s[3]||s[0]==s[1]) return false;
        return true;
    }
    return false;
}
int main(){
    cin>>n;
    int year1=n/10000;
    int month1=n%10000/100;
    int day1=n%100;
    for(int year=1000;year<=100000;year++)//题目中给的只是n的范围,并不是最后答案的范围,所以year要开的足够大
    for(int month=1;month<=12;month++)
    for(int day=1;day<=31;day++){
        if(month==1||month==3||month==5||month==7||month==8||month==10||month==12);
        else if(month==2){
            if((year%4==0&&year%100!=0)||year%400==0){
                if(day>29) break;
            }
            else{
                if(day>28) break;
            }
        }
        else{
            if(day>30) break;
        }
        if(flag1==1){
        sprintf(ch+1,"%04d%02d%02d",year,month,day);
        string s;
        for(int i=1;i<=8;i++){
                s+=ch[i];
        }
        if(!flag){
            if(check1(s)){
                cout<<s<<endl;
                flag=1;
            }
        }
        if(check2(s)){
            cout<<s<<endl;
            return 0;
        }
      }
      if(year==year1&&month==month1&&day==day1){
            flag1=1;
        }//标记在后面防止遍历到当前日期
    }
    return 0;
}

日期统计:

题目描述:

小蓝现在有一个长度为 100 的数组,数组中的每个元素的值都在 0 到 9 的范围之内。数组中的元素从左至右如下所示:

5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2
7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1
0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3

现在他想要从这个数组中寻找一些满足以下条件的子序列:
1、子序列的长度为 8;
2、这个子序列可以按照下标顺序组成一个 yyyymmdd 格式的日期,并且要求这个日期是 2023 年中的某一天的日期,例如 20230902,20231223。yyyy 表示年份,mm 表示月份,dd 表示天数,当月份或者天数的长度只有一位时需要一个前导零补充。
请你帮小蓝计算下按上述条件一共能找到多少个不同的 2023 年的日期。
对于相同的日期你只需要统计一次即可。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

code:

#include<iostream>
using namespace std;
int a[110];
int main(){
    for(int i=1;i<=100;i++){
        cin>>a[i];
    }
    char s[15];
    int cnt=0,flag=0;
    for(int year=2023;year<=2023;year++)
    for(int month=1;month<=12;month++)
    for(int day=1;day<=31;day++){
        if(month==1||month==3||month==5||month==7||month==8||month==10||month==12);
        else if(month==2){
            if(year%4==0&&year%100!=0||year%400==0){
                if(day>29) break;
            }
            else{
                if(day>28) break;
            }
        }
        else{
            if(day>30) break;
        }
        sprintf(s,"%04d%02d%02d",year,month,day);
        int m=0;
        for(int n=1;n<=100;n++){
            if(a[n]==(s[m]-'0')){
                m++;
                if(m==8) break;
            }
        }
        if(m==8) flag=1;
        if(flag==1){
            cnt++;
            flag=0;
        }
    }
    cout<<cnt<<endl;
    return 0;
}
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值