5.字符串

每个常用字符都对应一个-128~127的数字 ,二者之间可以相互转化: (int)97 , (char)a 常用ASCII值:’A’-‘Z’ 是65~90,’a’-‘z’是97-122,’0’-‘9’是 48-57 字符可以参与运算,运算时会将其当做整数

字符数组: 字符串就是字符数组加上结束符’\0’ 可以使用字符串来初始化字符数组,但此时要注意,每个字符串结尾会暗含一个’\0’字符,因此字符数组的长度至少要比字符串的长度多1!

初始化案例: 在这里插入图片描述

760. 字符串长度

给定一行长度不超过 100 的非空字符串,请你求出它的具体长度。

输入格式 输入一行,表示一个字符串。注意字符串中可能包含空格。

输出格式 输出一个整数,表示它的长度。

数据范围 1≤字符串长度≤100 字符串末尾无回车

输入样例: I love Beijing. 输出样例: 15

字符串就用cin和cout【string与scanf读入类型不匹配CE】 C++ 代码(常用):getline(cin,str)读取一行

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    string str;
    getline(cin,str); 
    cout << str.size() << endl;
    return 0;
}

cin.get()

#include <iostream>
#include <cstring>

using namespace std;

const int N = 105;

char str[N];

int main()
{
    cin.get(str, N);//需要注意cin.get()不会把换行符取出删除,影响下一次读入! 
    //cin.getline(str,N);//需要注意cin.getline()会把换行符取出删除,不影响下一次读入!
    cout << strlen(str) << endl;
    return 0;
}
//C语言代码
// #include<string.h>
// #include<stdio.h>

// int main()
// {
//     char s[105];
//     gets(s); //c++17, 总之之后被禁用了
//     printf("%d",strlen(s));
//     return 0;
// }

761. 字符串中的数字个数

输入一行字符,长度不超过 100,请你统计一下其中的数字字符的个数。

输入格式 输入一行字符。注意其中可能包含空格。

输出格式 输出一个整数,表示字数字字符的个数。

输入样例: I am 18 years old this year. 输出样例: 2

纯c++11

#include<iostream>

using namespace std;

int cnt;

int main()
{
    string word;
    while(cin >> word) //或者getline(cin,str); 空格不是数字不影响
        for(auto x: word) cnt += isdigit(x);
    cout << cnt;
}

朴素版

#include<iostream>
using namespace std;

int main()
{
    string a;
    getline(cin,a);
    int ans = 0;
    for(int i = 0; i < a.size(); i ++)
    {	//if(a[i] <= '9' && a[i] >= '0')
        if(isdigit(a[i]))     
        {
            ans ++;
        }
    }
    cout << ans << endl;

    return 0;
}

scanf一次读取版

scanf不能接收空格符,遇到空格就结束读入, 不能像C语言的gets()函数读取一行字符串(包括空格), 但scanf使用%[^\n]可以读取一行,直到碰到'\n'才结束读入

#include<iostream>
#include<cstring>

using namespace std;

const int N = 105;

char str[N];
int res;

int main()
{
    
    scanf("%[^\n]",str); //只读取某些字符  [^\n]即过滤'\n' : 只读入非'\n'
    int len = strlen(str);
    for(int i = 0;i < len; i++)res += isdigit(str[i]); //是数字返回true 即1
    printf("%d", res);
    return 0;
}

scanf分次读取版

isdigit(s[i])函数 :判断第i位是否为数字 ,是返回true

#include<iostream>
#include<cstring>

using namespace std;  //scanf("%s",s)!=EOF , 判断数字函数 isdigit 

const int N = 105;

char word[N];
int cnt;

int main()
{
    while(scanf("%s", word) != EOF) //每个单词判断
    {
        int len = strlen(word);
        for(int i = 0;i < strlen(word); i++) cnt += isdigit(word[i]);
    }
    printf("%d", cnt);
    return 0;
}

ch单个字符读取版

单字符char ch不断取位判断 ,if(ch==EOF)break; 结束

#include<iostream>
#include<cstring>

using namespace std;

int res;
char ch;

int main()
{    
    while(ch = getchar())
        if(ch == EOF) break;
        else res += isdigit(ch);
    cout << res;
}

L1y佬的补充

#include<bits/stdc++.h>
using namespace std;
int main(){
    string s;
    getline(cin,s);
    cout<<count_if(s.begin(),s.end(),[&](char c) { return isdigit(c); });
}

762. 字符串匹配

给定两个长度相同的字符串 a 和字符串 b。

如果在某个位置 i 上,满足字符串 a 上的字符 a[i] 和字符串 b 上的字符 b[i] 相同,那么这个位置上的字符就是匹配的。

如果两个字符串的匹配位置的数量与字符串总长度的比值大于或等于 k,则称两个字符串是匹配的。

现在请你判断给定的两个字符串是否匹配。

输入格式 第一行包含一个浮点数 k,第二行包含字符串 a,第三行包含字符串 b。

输入的字符串中不包含空格。

输出格式 如果两个字符串匹配,则输出 yes。

否则,输出 no。

数据范围 0≤k≤1, 字符串的长度不超过 100。

输入样例: 0.4 abcde xbacd 输出样例: no

如果两个长度相同字符串的匹配位置的数量与字符串总长度的比值大于或等于 k,则称两个字符串是匹配的

#include<iostream>  

using namespace std;

double k, cnt;
string s1, s2;

int main()
{
    cin >> k >> s1 >> s2;
    for(int i = 0;i < s1.size(); i++) if(s1[i] == s2[i]) cnt++; //统计相同字符个数
    if(cnt / s1.size() >= k) puts("yes"); //相同部分所长比值是否超过k
    else puts("no");
}

763. 循环相克令

循环相克令是一个两人玩的小游戏。

令词为“猎人、狗熊、枪”,两人同时说出令词,同时做出一个动作——猎人的动作是双手叉腰;狗熊的动作是双手搭在胸前;枪的动作是双手举起呈手枪状。

双方以此动作判定输赢,猎人赢枪、枪赢狗熊、狗熊赢猎人,动作相同则视为平局。

现在给定你一系列的动作组合,请你判断游戏结果。

输入格式 第一行包含整数 T,表示共有 T 组测试数据。

接下来 T 行,每行包含两个字符串,表示一局游戏中两人做出的动作,字符串为 Hunter, Bear, Gun 中的一个,这三个单词分别代表猎人,狗熊和枪。

输出格式 如果第一个玩家赢了,则输出 Player1。

如果第二个玩家赢了,则输出 Player2。

如果平局,则输出 Tie。

数据范围 1≤N≤100 输入样例 3 Hunter Gun Bear Bear Hunter Bear 输出样例 Player1 Tie Player2

unordered_map<int, string>映射

#include<iostream>
#include <unordered_map>   

using namespace std;

int n;
string s1, s2;

int main()
{   //写全局会和库函数中的hash冲突: 解决法:可以写heap  或者map(映射) 
    unordered_map<int , string> hash;   //映射的下一个(取模) 等于s2则 s1 < s2, 先判断是不是相等 , 
    hash[0] = "Hunter", hash[1] = "Bear", hash[2] = "Gun"; //在取模3的值域映射下标:关系: 0H < 1S < 2G , 2 < 0   
    cin >> n;
    while (n -- )
    {
        cin >> s1 >> s2;
        int a, b;//Player1和Player2的映射值
        for(int i = 0; i < 3; i++)
        {
            if(hash[i] == s1) a = i;
            if(hash[i] == s2) b = i;
        }
        if(a == b) puts("Tie");
        else if((a + 1) % 3 == b) puts("Player2"); //(a + 1) % 3 == b : 判断Player1下一位是否为Player2, 否则Player1
        else puts("Player1");
    }
    return 0;
}

闫式封装函数-映射

#include <iostream>

using namespace std;

int get(string s)  //映射值
{//转换成数字 ,再依据规则  x == y  ,(x + 1) % 3 == y【关键】
    if (s == "Hunter") return 0;
    if (s == "Bear") return 1;
    return 2;
}

int main()
{
    int n;
    cin >> n;
    while (n -- )
    {
        string a, b;
        cin >> a >> b;

        int x = get(a), y = get(b);
        if (x == y) puts("Tie");
        else if ((x + 1) % 3 == y) puts("Player2");  //关键点 - 逻辑
        else puts("Player1"); ;
    }
    return 0;
}

old_code-朴素 观察长度不同

#include <btis/stdc++.h>
using namespace std;

int main()
{
    int n;
    cin >> n;

    string x, y;
    while (n --)
    {
        cin >> x >> y; //string ,scanf不能直接读 
        int a = x.size(), b = y.size();
        if (a - b == -1 || a - b == -2 || a - b == 3)  //观察长度不同
            cout << "Player1" << endl;
        else if (a == b)
            cout << "Tie" << endl;
        else cout << "Player2" << endl;
    }

    return 0;
}

朴素枚举胜利情况


#include<bits/stdc++.h>
using namespace std;
int main (){
    int t;
    cin>>t;
    while(t--){
        string a,b;  //string ---cin
        cin>>a>>b;
        if(a==b)puts("Tie");
        else if(a=="Hunter"&&b=="Gun"||a=="Bear"&&b=="Hunter"||a=="Gun"&&b=="Bear")  
        puts("Player1");
                else puts("Player2");
    }
    return 0;
}

764. 输出字符串

给定一个字符串 a,请你按照下面的要求输出字符串 b。

给定字符串 a 的第一个字符的 ASCII 值加第二个字符的 ASCII 值,得到 b 的第一个字符;

给定字符串 a 的第二个字符的 ASCII 值加第三个字符的 ASCII 值,得到 b 的第二个字符;

给定字符串 a 的倒数第二个字符的 ASCII 值加最后一个字符的 ASCII 值,得到 b 的倒数第二个字符;

给定字符串 a 的最后一个字符的 ASCII 值加第一个字符的 ASCII 值,得到 b 的最后一个字符。

输入格式 输入共一行,包含字符串 a。注意字符串中可能包含空格。

数据保证字符串内的字符的 ASCII 值均不超过 63。

输出格式 输出共一行,包含字符串 b。

数据范围 2≤a的长度≤100 输入样例: 1 2 3 输出样例: QRRSd

模拟

#include <iostream>

using namespace std;

int main()
{
    string a;
    getline(cin, a);
    for(int i = 0; i < a.size() - 1; i++)
    {
        cout << char(a[i] + a[i + 1]);  //直接输出 
    }
    cout << char(a[a.size() - 1] + a[0]); //特别处理最后一个 
    return 0;
}

规律映射做:[是选择别难为自己还是提升自己]

#include <iostream>

using namespace std;

int main() {
    string a;
    getline(cin, a);
    for(int i = 0; i < a.size(); i ++)
        cout << (char)(a[i] + a[(i + 1) % a.size()]);   //最后一个a[a.size() - 1] + a[0] :(映射可能值区间)总长度  [尾部-首部]  
    return 0;
}

765. 字符串加空格

给定一个字符串,在字符串的每个字符之间都加一个空格。

输出修改后的新字符串。

输入格式 共一行,包含一个字符串。注意字符串中可能包含空格。

输出格式 输出增加空格后的字符串。

数据范围 1≤字符串长度≤100 输入样例: test case 输出样例: t e s t c a s e

简单版

#include<iostream>

using namespace std;

int main()
{
    string str;
    getline(cin, str); 
    for(char &c : str) cout << c << ' ';    //对string中的单个字符修改的时候才用&【可以不加】
}

试试scanf("%[^\n]", str);

#include<iostream>
#include<cstring>
using namespace std;

const int N = 105;
char str[N];    
string res;  //res[i]为char类型

int main()
{
    scanf("%[^\n]", str);
    int len = strlen(str);
    for(int i = 0; i < len; i++)
    {
        res += str[i];
        res += ' ';
    }
    cout << res ;
    return 0;
}

766. 去掉多余的空格

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

输入格式 共一行,包含一个字符串。

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

数据范围 输入字符串的长度不超过 200。 保证输入字符串的开头和结尾没有空格。

输入样例: Hello world.This is c language. 输出样例: Hello world.This is c language.

最简版

方法一:利用cin在输入时不会读入[空格|Tab|回车]。

#include<iostream>

using namespace std;

int main()
{
    string s;
    while(cin >> s)
        cout << s <<" ";
    return 0;
}

与运算-2022mycode版

不能有两个连续空格

#include<iostream>
#include<cstring>

using namespace std;

int main()
{
    string str, res;
    getline(cin, str);
    for(int i = 0 ; i < str.size() ; i++)
    {
        while(str[i] == ' ' && str[i + 1] == ' ') i++;//遇到多个空格跳过,只保留最后一个
        res += str[i];
    }
    cout << res;
    return 0;
}

或运算

#include <iostream>
using namespace std;

int main()
{
    string s;
    getline(cin, s);
    for(int i = 0; i < s.size(); i++)
        if(s[i] != ' ' || s[i+1] != ' ') cout << s[i]; //一连串空格, 最后一个空格保留
    return 0;
}

复杂版hh

#include <iostream>

using namespace std;

int main()
{
    string a ;
    getline(cin,a);
    for(int i = 0 ; i < a.size() ; i ++ )
    {
        if(a[i] == ' ') //检测到空格
        {
            cout << ' ';//只输出一个空格,删去多余的空格
            while(a[i + 1] == ' ') i++; //检测下一个是不是空格,是的话就跳过(i++) 
        }
        else cout << a[i];
    }
}

767. 信息加密

在传输信息的过程中,为了保证信息的安全,我们需要对原信息进行加密处理,形成加密信息,从而使得信息内容不会被监听者窃取。

现在给定一个字符串,对其进行加密处理。

加密的规则如下:

字符串中的小写字母,a 加密为 b,b 加密为 c,…,y 加密为 z,z 加密为 a。 字符串中的大写字母,A 加密为 B,B 加密为 C,…,Y 加密为 Z,Z 加密为 A。 字符串中的其他字符,不作处理。 请你输出加密后的字符串。

输入格式 共一行,包含一个字符串。注意字符串中可能包含空格。

输出格式 输出加密后的字符串。

数据范围 输入字符串的长度不超过 100。

输入样例: Hello! How are you! 输出样例: Ifmmp! Ipx bsf zpv!

mycode2022

#include<iostream>

using namespace std;

int main()
{
    string str;
    getline(cin, str);
    
    for(int i = 0; i < str.size(); i++)
        if(isalpha(str[i])) //先判断是不是字符
        {
            if(str[i] >= 'a' && str[i] <= 'z') str[i] = (str[i] - 'a' + 1) % 26 + 'a';
            else str[i] = (str[i] - 'A' + 1) % 26 + 'A';
        }
    
    cout << str;
        
    return 0;
}

string类型 for(autu c: str)

char类型转int的ASCLL码偏移量: c - 'a'
(映射 - 减去区间第一个值【偏移值】: 相当于平移到起点, 如0)

#include<iostream>

using namespace std;

int main()
{
    string str;
    getline(cin, str);
    
    for (auto &c : str) //加&修改
        if(c >= 'a' && c <= 'z') c = (c - 'a' + 1) % 26 + 'a'; //小写字符偏移加密
        else if (c >= 'A' && c <= 'Z') c = (c - 'A' + 1) % 26 + 'A';  //大写字符偏移加密
    
    cout << str;
        
    return 0;
}

单个字符修改版

scanf不会过滤空格哦!

#include<iostream>

using namespace std;

int main()
{
    char ch;
    while(scanf("%c",&ch) == 1) //有读入即使是空格,回车也会继续循环
    {
        if(ch >= 'a' && ch <= 'z') ch = (ch-'a' + 1 ) % 26 + 'a';
        else if(ch >= 'A' && ch <= 'Z') ch = (ch - 'A' + 1) % 26 + 'A';
        cout << ch;
    }
    return 0;
}

不动脑子法
#include<bits/stdc++.h>
using namespace std;

int main(){
    string a;
    getline(cin,a);
    for(int i=0;i<a.size();i++){
        if(a[i]>='a'&&a[i]<'z'||a[i]>='A'&&a[i]<'Z')
        a[i]++;
        else if(a[i]=='z'||a[i]=='Z')a[i]-=25;
    }
    cout<<a<<endl;

    return 0;
}


枚举更菜法,但s[i]
#include<bits/stdc++.h>
using namespace std;

int main()
{
    string st;
    int i;
    getline(cin,st);
    for (i=0;i<st.size();i++){
        if (st[i]>='a'&&st[i]<='y'||st[i]>='A'&&st[i]<='Y'){
            cout<<char(st[i]+1);
            continue;
        }//普通形式
        if (st[i]=='z'){ //可改if else就不用continue
            cout<<'a';
            continue;
        }//特殊
        if (st[i]=='Z'){
            cout<<'A';
            continue;
        }//特殊
        cout<<st[i];//输出这一项就ok了
    }
    return 0;
}

768. 忽略大小写比较字符串大小

一般我们用 strcmp 可比较两个字符串的大小,比较方法为对两个字符串从前往后逐个字符相比较(按 ASCII 码值大小比较),直到出现不同的字符或遇到 \0 为止。

如果全部字符都相同,则认为相同;如果出现不相同的字符,则以第一个不相同的字符的比较结果为准。

但在有些时候,我们比较字符串的大小时,希望忽略字母的大小,例如 Hello 和 hello 在忽略字母大小写时是相等的。

请写一个程序,实现对两个字符串进行忽略字母大小写的大小比较。

输入格式 输入为两行,每行一个字符串,共两个字符串。注意字符串中可能包含空格。

数据保证每个字符串的长度都不超过 80。

输出格式 如果第一个字符串比第二个字符串小,输出一个字符 <。

如果第一个字符串比第二个字符串大,输出一个字符 >。

如果两个字符串相等,输出一个字符 =。

输入样例: Hello hello

输出样例:

=

tolower(char c)函数

先全部转小写再比较大小 注意字符串中可能包含空格,此题不能cin(空格会结束!!!), 需用getline(cin,a);


#include<iostream>

using namespace std;

int main()
{
    string a, b;
    getline(cin, a);
    getline(cin, b);
    for(auto &c: a) c = tolower(c);  //不加&只能使用字符串的值,加了&就可以使用和修改值 
    for(auto &c: b) c = tolower(c); //tolower转换成小写的函数 
    if(a == b) puts("=");
    else if(a > b) puts(">");
    else if(a < b) puts("<");
}

比较strcmp(a.c_str(),b.c_str())返回值 + string.c_str()转char[]

#include <iostream>
#include <string>
#include <cstring>

using namespace std;

int main()
{
    string a, b;
    getline(cin, a);//注意字符串中可能包含空格,此题不能cin 空格会结束 !! ,用getline(cin,a);  
    getline(cin, b);

    for (int i = 0; i < a.size(); i ++) //a97, A65
        if (a[i] >= 'A' && a[i] <= 'Z') a[i] += 32;

    for (int i = 0; i < b.size(); i ++)
        if (b[i] >= 'A' && b[i] <= 'Z') b[i] += 32;

    int c;
    c = strcmp(a.c_str(),b.c_str());  //char[]型比较函数 : 先a.c_str() : string转char[]         
    if(c < 0) cout << "<";
    if(c == 0) cout << "=";
    if(c > 0) cout << ">";

    return 0;
}
// if(s1.size()>s2.size())  //提前剪枝
// {
//     puts(">");return 0;
// }
// if(s1.size()<s2.size())
// {
//     puts("<");return 0;
// } 

769. 替换字符

给定一个由大小写字母构成的字符串。

把该字符串中特定的字符全部用字符 # 替换。

请你输出替换后的字符串。

输入格式 输入共两行。

第一行包含一个长度不超过 30 的字符串。

第二行包含一个字符,表示要替换掉的特定字符。

输出格式 输出共一行,为替换后的字符串。

输入样例: hello l 输出样例: he##o

#include<iostream>

using namespace std;

int main()
{
    string str;
    char ch;
    cin >> str >> ch;
    for(auto &c: str)
        if(c == ch) c = '#';
    cout << str;
    return 0;
}

770. 单词替换

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

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

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

输入格式 输入共 3 行。

第 1 行是包含多个单词的字符串 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

全部存入string word[N]

#include<iostream>
#include<cstring>

using namespace std;

const int N = 105;
string word[N];
int cnt;

int main()
{
    while(cin >> word[cnt]) cnt ++; //按word单词全部读入【 不要写成 cin >> word[cnt ++] 可能优先级或者结合错误,总之下标混乱】
    
    string a = word[cnt - 2], b = word[cnt - 1]; 
    for(int i = 0; i < cnt - 2; i++)
        if(word[i] == a) cout<< b <<" ";
        else cout << word[i] <<" ";
    return 0;
}

string函数复合使用

#include <iostream> 

using namespace std;

int main()
{
    string s, a, b;
    getline(cin, s);
    cin >> a >> b;//替换目标,替换值
    s = ' ' + s + ' ';    // 把单词和语句前后都加上空格 便于查找!!!
    a = ' ' + a + ' ';
    b = ' ' + b + ' ';

    while(s.find(a) != string::npos)  // 一直查找 找到就替换  没找到返回值string::npos   (npos模板参数名称)
        s.replace(s.find(a), a.size(), b); //找到a, 把a替换为b
    
    // 把加进去的首尾空格都删除
    s.erase(s.begin());    //等效s1.erase(0, 1);  【配合使用迭代器删除首元素】
    s.erase(s.end() - 1);  //或者s1.erase(s1.size() - 1);
    
    cout << s;
    return 0;
}

用正则表达式替换单词

#include <iostream>
#include <string>
#include <regex> //正则表达式
using namespace std;
int main()
{
    string s, a, b;
    getline(cin, s);
    cin >> a >> b;
    cout << regex_replace(s,regex("\\b" + a + "\\b"),b) << endl;
   
    return 0;
}  

string类型 s1.find(s2); // 在 s1 中查找字符串 s2,找到返回 s2 首字母在字符串中的下标,找不到返回 -1
s1.replace(pos, len, s2); // 把 s1 中从下标 pos 开始的长度为 len 的子串替换为 s2 s1.erase(it); // 把 s1 字符串中迭代器 it 处的字符删除
s1.erase(pos, len); // 把 s1 中从下标 pos 开始的长度为 len 的子串删除

详细总结跳转查看

771. 字符串中最长的连续出现的字符

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

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

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

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

输入样例: 2 aaaaabbbbbcccccccdddddddddd abcdefghigk 输出样例: d 10 a 1

mycode2022 题目:字符串中无空白字符(空格、回车和 tab)---> 用cin读入

#include<iostream>
#include<cstring>

using namespace std;

int main()
{
    int n;
    cin >> n;
    string str;
    while (n -- )
    {
        cin >> str;
        char ch = str[0];
        int cnt = 1, max_cnt = 0; 
        for(int i = 0; i < str.size(); i++)
        {
            while(i + 1 < str.size() && str[i] == str[i + 1]) cnt ++, i++;
            if(max_cnt < cnt) max_cnt = cnt, ch = str[i];
            cnt = 1; 
        }
        cout << ch << " " << max_cnt << endl;
    }
    
    return 0;
}

y总双指针

题目:字符串中无空白字符(空格、回车和 tab)

算法
(双指针) O(n×T)
使用双指针扫描每一个test case,并记录下最大长度与该长度下的字符即可。

时间复杂度
每个test case的字符串会被扫描一次,总共T个test case,所以总复杂度为O(n×T)。

#include <iostream>
using namespace std;
int main()
{
    int T;
    cin >> T;
    while(T --)
    {
        int maxn = -1;//maxn记录最大长度
        string str, maxs;//maxs记录最大长度时的字符
        cin >> str;
        for(int i = 0; i < str.size(); i ++)
        {
            int j = i;
            int cnt = 0;
            while(str[j] == str[i] && j < str.size())//当指针j没有越界且与指针i的内容相同时移动
                j ++, cnt ++;
            if(cnt > maxn)//更新最大值
                maxn = cnt, maxs = str[i];
            i = j - 1;//判断下一个位置
        }
        cout << maxs << " " << maxn << endl;
    }
}

772. 只出现一次的字符

给你一个只包含小写字母的字符串。

请你判断是否存在只在字符串中出现过一次的字符。

如果存在,则输出满足条件的字符中位置最靠前的那个。

如果没有,输出 no。

输入格式 共一行,包含一个由小写字母构成的字符串。

数据保证字符串的长度不超过 100000。

输出格式 输出满足条件的第一个字符。

如果没有,则输出 no。

输入样例: abceabcd 输出样例: e

从前往后查找与从后向前查找同一个字符,如果位置一样那该字符就直出现一次,因为是从第一个开始查找所以找出的是第一个只出现一次的字符

s.find()和s.rfind() 夹逼

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
    string s;
    bool flag = false;
    while(getline(cin, s)) //可能包含空格 
    {
        for(int i = 0;i < s.size(); i++)
        {
            if(s.find(s[i]) == s.rfind(s[i])) //正序查找第一个下标 == 逆序查找第一个下标 :等效有且仅有一个元素
            {
                cout << s[i] << endl;
                flag = true;
                break;
            }
        }
    }
    if(!flag) puts("no");
    return 0;
}

去掉标记版

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
    string s;
    while(getline(cin, s)) //可能包含空格 
    {
        for(int i = 0;i < s.size(); i++)
        {
            if(s.find(s[i]) == s.rfind(s[i]))  //正序 == 逆序  等效有且仅有一个元素
            {
                cout << s[i] << endl;
                return 0; //省标记【但多轮输入只能break】
            }
        }
    }
    puts("no");
    return 0;
}

cnt统计1

#include<iostream>
using namespace std;

const int N = 150; //97开始 + 

int cnt[N];
int main()
{
    string s;
    cin >> s;
    //虽然不改s, 但是有时会没加&而调试
    for(auto &i: s)//遍历字符串  ,对应字符ASCLL位置++  : 优化映射26,数组开26即可 【i-'a'】 【yxc:写代码不要难为自己!!!】
    {
        cnt[i] ++;    //(int)(i-'a') [好像自动转整数]
        printf("%d ", i);
    }
        
    for(auto &i: s)  //遍历字符串
        if(cnt[i] == 1)  //i值即 s[i]   
        {
            cout << i << endl;
            return 0; //省一个标记
        }
    cout << "no" << endl;
    return 0; 
}

cnt统计2

#include<iostream>
#include<cstring>

using namespace std;

const int N = 30; //映射0-25

int cnt[N];

int main()
{
    string s;
    cin >> s;
    for(int i = 0; i < s.size(); i++) cnt[s[i] - 'a']++;  //s.size()返回值类型。。
          
    for(int i = 0; i < s.size(); i++)
        if(cnt[s[i] - 'a'] == 1) 
        {
            cout << s[i] << endl;
            return 0;
        }
    
    puts("no");
    
    return 0;
}

773. 字符串插入

有两个不包含空白字符的字符串 str 和 substr,str 的字符个数不超过 10,substr 的字符个数为 3。(字符个数不包括字符串结尾处的 \0。)

将 substr 插入到 str 中 ASCII 码最大的那个字符后面,若有多个最大则只考虑第一个。

输入格式 输入包括若干行,每一行为一组测试数据,格式为

str substr

输出格式 对于每一组测试数据,输出插入之后的字符串。

输入样例: abcab eee 12343 555 输出样例: abceeeab 12345553

str.insert(下标位置从0开始, 插入sub)

#include <iostream>
#include<cstring>

using namespace std;

int main()
{
    string str, sub;
    while(cin >> str >> sub)  
    {
        int pos = 0;
        for(int i=0; i < str.size(); i++)
            if(str[i] > str[pos])  //找对应ASCLL码max的字符下标位置,多个相同选取第一个
            {
                pos = i;
            }
        str.insert(pos + 1, sub); //插入str中ASCII 码最大的那个字符的后面
        cout << str << endl;
    }
}

774. 最长单词

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

输入格式 输入这个简单英文句子,长度不超过 500。

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

输入样例: I am a student of Peking University. 输出样例: University

mycode2022

#include<iostream>
#include<cstring>

using namespace std;

int main()
{
    string str, res;
    int max_len = 0;
    while(cin >> str)
    {
        if(str.back() == '.') str.pop_back();   //或者str.erase(str.size() - 1, 1); 
        if(str.size() > max_len) 
        {
            max_len = str.size();
            res = str;
        }
    }
    cout << res << endl;
    return 0;
}

双指针-截取每个单词(比函数快)

#include <iostream>
using namespace std;

int cnt, maxn;
string s, res, tmp;

int main()
{
    getline(cin,s);
    
    for (int i = 0; i < s.size(); i++)
    {  
        
        for (int j = i; s[j] != '.' && s[j] != ' '; j ++)
        {
            tmp = tmp + s[j];
            cnt++;
        }
        
        if (maxn < cnt) 
        {
            maxn = cnt;
            res = tmp;
        }
        i += cnt; //判断下一个单词:移到下个单词开头
        cnt= 0;//每轮遍历状态初始化!!
        tmp = "";
    }
    
    cout << res << endl;//空字符串就打印为空

    return 0;
}

others : str.erase()


#include<cstring>
#include<iostream>
using namespace std;
string l,lmax;
int len,maxx,f;
int main(){
    while(cin>>l){
        len=l.size();
        if(l[len-1]=='.'){ //最后一个
            len--;
            l.erase(len,1);
            f=1;
        }
        if(len>maxx){
            lmax=l;
            maxx=len;
        }
        if(f) break; //空字符串,没有'.'结尾
    }
    cout<<lmax ;
    return 0;
}

775. 倒排单词

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

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

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

输入样例: I am a student 输出样例: student a am I

字符串倒序拼接-多个拼接

#include<iostream> // string

using namespace std;

int main()
{
    string str, res;    
    while(cin >> str)
    {
        res = str + " " + res; //可以多个加号连用!!!
    }
    cout << res << endl;
        
    return 0;
}

cnt统计

#include <iostream>
using namespace std;

const int N = 105;
int cnt;
string s[N];

int main()
{
    
    while(cin >> s[cnt]) cnt ++;
    while(cnt -- ) cout << s[cnt] <<" ";
    return 0;
}

776. 字符串移位包含问题

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

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

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

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

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

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

输入样例: AABCD CDAA 输出样例: true

string::find()与string::npos 自身拼接且遍历 :可以得到所有循环子串

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

int main()
{
    string a, b, s;
    cin >> a >> b;
    if(a.size() < b.size()) swap(a, b); //题目其中一个, 选取长为主串, 另一个为模式串
    s = a + a;
    if(s.find(b) != string::npos) puts("true"); //find函数寻找子串   
    else puts("false");
    return 0;
}

string.find()若没有找到,相当于不为空 :string字符串就会返回一个特殊的标记npos (类似n长度的pos位置) string::npos 等于 -1 或者 4294967295 size_t类型: 所能达到的最大长度,它是无符号整数 //这种整数用来记录一个大小(size)。size_t的全称应该是size type,就是说“一种用来记录大小的数据类型”

完整知识点链接

string::find()函数:是一个字符或字符串查找函数, 该函数有唯一的返回类型, 即string::size_type string::size_type, 定义无符号整形类型,可能是整数也可能是长整数。 如果查找成功,返回按照查找规则找到的第一个字符或者子串的位置 如果查找失败,返回string::npos,即-1(但结果不是-1,而是一个很大的数值,那是因为它是无符号的)

string::npos是这样定义的:static const size_type npos = -1; 因为string::size_type描述的是size,故需为无符号整数型类别。 因为缺省配置为size_t作为size_type,于是-1被转换为无符号整数类型,npos也就成为了该类别的最大无符号值。 不过实际值还是取决于size_type的实际定义类型,即无符号整型(unsigned int)的-1与无符号长整型(unsigned long)的-1是不同的。

#include <iostream>
#include <string>

using namespace std;

bool check(string a, string b)
{
    int len = a.size();
    a += a; //复制字符串并连接
    //if (a.find(b) >= 0 && a.find(b) < len) return true; //判断是否包含
    if (a.find(b) != string::npos) return true; //判断a中是否包含b
    return false;
}

int main()
{
    string a, b;
    cin >> a >> b;
    if (check(a, b) || check(b, a)) cout << "true";
    else cout << "false";
    return 0;
}

777. 字符串乘方

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

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

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

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

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

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

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

输入样例: abcd aaaa ababab . 输出样例: 1 4 3

枚举子串看能否拼接成字符串

#include<iostream>
#include<cstring>

using namespace std;

int main()
{
    string str;
    while(cin >> str && str != ".")
    {
        //if(str == ".") return 0; 
        for(int i = 1; i <= str.size(); i++)
        {
            string sub = str.substr(0, i);  //string sub = string(str, 0, i); 
            if(str.size() % sub.size() != 0) continue; //剪枝:不可能是周期
            string sub_concat = sub;
            while(sub_concat.size() < str.size()) sub_concat += sub; //能否由子串组成字符串str
            if(sub_concat == str)
            {
                cout<< (str.size() / sub.size()) <<endl; // n子串个数 = 字符串总长 / 子串长
                break;
            }
        }
    }
    return 0;
}

cnt统计

#include<iostream>
#include<cstring>

using namespace std;

int main()
{
    string str;
    while(cin >> str)
    {
        if(str == ".") return 0;
        for(int i = 1; i <= str.size(); i++)
        {
            int cnt = 1;//统计子串个数
            string sub = str.substr(0, i);
            if(str.size() % sub.size() != 0) continue; //剪枝:不可能是周期
            string concat_sub = sub;
            while(concat_sub.size() < str.size()) concat_sub += sub, cnt++; //子串拼接次数cnt++ 
            if(concat_sub == str)
            {
                cout<< cnt << endl; // n子串个数 = 字符串总长 / 子串长
                break;
            }
        }
    }
    return 0;
}

y总朴素版:双指针

#include <iostream>

using namespace std;

int main()
{
    string str;
    while (cin >> str, str != ".")
    {
        int k = 1;
        while (k <= str.size()) //枚举周期长度(子串长度)为k
        {
            if (str.size() % k == 0)
            {
                bool flag = true;
                for (int i = k; i < str.size(); i += k) //希尔排序
                    for (int j = 0; j < k; j ++ ) 
                        if (str[j] != str[i + j]) //比较是否相等
                            flag = false;
                if (flag) break; //找到周期子串
            }
            k ++ ;
        }

        cout << str.size() / k << endl; //n乘方 = 子串个数
    }

    return 0;
}

778. 字符串最大跨距

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

现在,我们想要检测 S1 和 S2 是否同时在 S 中出现,且 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

思路: 找第一个s1和最后一个s2[有点贪心最优解] string成员函数 s.find(字符串); 从前往后返回第一个位置下标, 找不到返回 -1 s.rfind(字符串); 从后往前返回第一个位置下标, 找不到返回 -1

mycode2022

#include <iostream>
#include <cstring>
#include<cstdio>

using namespace std;

int main()
{
    string s, s1, s2;
    char ch;
    int i = 0;
    while(cin >> ch)
    {
        if(ch != ',')
        {
            if(i == 0) s += ch;
            else if(i == 1) s1 += ch;
            else s2 += ch;
        }
        else i ++; //第一次遇到',' i == 1, 第二次遇到',' i == 2
    }
    //为了保证s1在s2的左边且互不交叉, s2逆序寻找[找最优解]
    int l = s.find(s1), r = s.rfind(s2); //l:s1的位置 , r: s2的位置 
    if(l != -1 && r != -1 && l + s1.size() - 1 < r) printf("%d", r - l - s1.size() ); //输出下标差值距离 
    else puts("-1");  //不存在输出-1
    
    return 0;
}

y总

#include <iostream>

using namespace std;

int main()
{
    string line;
    cin >> line; //读入一行-无空格

    string a, b, c; //【字符串截取a, b, c】
    int k = 0;
    while (line[k] != ',') a += line[k ++ ]; 
    k ++ ;
    while (line[k] != ',') b += line[k ++ ];
    k ++ ;
    while (k < line.size()) c += line[k ++ ];

    int l = 0;  //模拟find:从左到右找
    while (l < a.size())  
    {
        if (a.substr(l, b.size()) == b) break;
        l ++ ;
    }

    int r = a.size() - 1;
    while (r >= 0) //模拟rfind:从右到左找
    {
        if (a.substr(r, c.size()) == c) break;
        r -- ;
    }

    if (l + b.size() <= r) cout << r - l - b.size() << endl; //找不到子串则走到边界,也是不满足此条件输出-1
    else cout << -1 << endl;

    return 0;
}

三月的风链接

#include <iostream> 

using namespace std;

int main()
{
    string s, s1, s2, a;
    getline(cin, a);

    int f1, f2;                      // 两个','的位置  读入处理【先寻找','位置下标,再用substr函数】
    f1 = a.find(','); 
    f2 = a.rfind(',');
    s = a.substr(0, f1);
    s1 = a.substr(f1 + 1, f2 - f1 - 1);
    s2 = a.substr(f2 + 1);


    int l, r;
    l = s.find(s1);                   // 在字符串s上从左往右找s1
    r = s.rfind(s2);                  // 在字符串s上从右往左找s2 [找最优解]

    if (l == -1 || r == -1)           // s1 或 s2 不在 s 上
    { 
        cout << "-1";
        return 0;
    }

    l = s.find(s1)  + s1.size() - 1;   // l为s1最右面的下标

    if ( l >= r )                      // s1 s2 交叉
        cout << "-1";
    else cout << r - l - 1;

    return 0;
}

779. 最长公共字符串后缀

给出若干个字符串,输出这些字符串的最长公共后缀。

输入格式 由若干组输入组成。

每组输入的第一行是一个整数 N。

N 为 0 时表示输入结束,否则后面会继续有 N 行输入,每行是一个字符串(字符串内不含空白符)。

每个字符串的长度不超过 200。

输出格式 共一行,为 N 个字符串的最长公共后缀(可能为空)。

数据范围 1≤N≤200 输入样例: 3 baba aba cba 2 aa cc 2 aa a 0输出样例: ba

a

相邻两个求相同后缀:比较取min求出公共后缀

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    int n;
    while(cin >> n, n)
    {
        string s, a;
        int len = 0x3f3f3f3f; //用min初始INF 
        cin >> s;
        for(int i = 1; i < n; i ++)
        {
            int res = 0;
            cin >> a;
            for(int j = 0; j < a.size() && j < s.size();  j ++)  //等效j < min(a.size(), s.size()) 
                if(a[a.size() - 1 - j] == s[s.size() - 1 - j]) res ++; //此轮公共后缀长度res
                else break;
            len = min(len, res); //取比较两两相邻后缀: 取最小值为公共后缀
        }
        if(len) cout << s.substr(s.size() - len) << endl;
        else cout << endl; //输出回车
    }
    return 0;
}

y总

#include <iostream>

using namespace std;

int main()
{
    string words[200];

    int n;
    while (cin >> n, n) 
    {
        for (int i = 0; i < n; i ++ ) cin >> words[i];

        int k = 1; //最长公共后缀长度:从1开始判断
        while (true)
        {
            bool flag = true; //false则否定此轮判断
            for (int i = 0; i < n; i ++ )
            {
                if (words[i].size() < k) //size < k : 公共后缀长度不可能大于k
                {
                    flag = false; 
                    break;
                }   //遍历所有与第一个判断: substr(起始下标从0开始, 截取长度)
                else if (words[i].substr(words[i].size() - k, k) != words[0].substr(words[0].size() - k, k))
                {
                    flag = false;
                    break;
                }
            }
            if (!flag) break;
            k ++ ;
        }

        k -- ; //上一轮k++ 但是判断不行后break, 则合理的最长公共后缀长度为k - 1
        cout << words[0].substr(words[0].size() - k, k) << endl;
    }

    return 0;
}

思想:把所有字符串首尾翻转,求公共后缀就变为求公共前缀

依次从前往后比较所有字符串每一位的字符是否相同,取所有字符串中最短的长度作为len 从第 0 位依次比较到第 len - 1 位,即可确定前几位是公共前缀。

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 210;

string s[N];

int main()
{
    int m;      // m个字符串
    while (cin >> m && m) 
    {
        int len = 200;
        for (int i = 0; i < m; i ++)
        {
            cin >> s[i];
            reverse( s[i].begin(), s[i].end() );         // 把每个字符串首尾翻转 变后缀为前缀
            if ( s[i].size() < len) len = s[i].size();   // 取所有字符串中最短长度作为len
        }

        string a;                           // 从前往后存放相同的字符 最后一位不一定属于公共前缀
        int l = -1;
        for(int i = 0; i < len; i ++)       // 从字符串第一位依次比较
        {
            a += s[0][i];                   // 把第一个字符串的第i个字符存到a[i]中用于与后面的比较
            for (int j = 1; j < m; j ++)
                if (a[i] != s[j][i])        
                {
                    l = i;                  // 把出现不同的位数存到l中
                    break;
                }
            if (l != -1) break;             // 已经知道前缀的位数 后面的没必要判断
        }

        if (l == -1)                        // 说明没出现过a[i] != s[j][i] a中的字符都是公共前缀
            for (int i = len - 1; i >= 0; i --)  // 因为翻转过 倒序输出
            cout << a[i];
        else
            for (int i = l - 1; i >= 0; i --)    // a的第l位字符不是公共前缀 l之前的字符都是
                cout << a[i];
        cout << endl;
    }
    return 0;
}