前言:
本篇文章包含字符串的一些基本操作,所选题目比较经典,解法易懂巧妙,期间还会有一些补充拓展。题目稍多,希望大家耐心看完、有所收获
主要内容:
1、字符串插入:
题目介绍:
有两个不包含空白字符的字符串 str和 substr,str的字符个数不超过 10,substr 的字符个数为 3(字符个数不包括字符串结尾处的 \0)
将 substr插入到 str中ASCII 码最大的那个字符后面,若有多个最大则只考虑第一个。
输入样例:
abcab eee
12343 555
输出样例:
abceeeab
12345553
代码详解:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string a,b;
while(cin>>a>>b)
{
int p=0;
for(int i=1;i<a.size();i++)
if(a[i]>a[p]) p=i; //找到最大的ASCII 码所在下标
cout<<a.substr(0,p+1)+b+a.substr(p+1)<<endl; //利用substr函数输出
}
return 0;
}
加餐小灶:
substr的返回值,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
异常 :若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾
例如:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s="sfsa";
string a=s.substr(0,3);//输出sfs
string b=s.substr(); //输出sfsa
string c=s.substr(2,3); //输出sa
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
return 0;
}
2、只出现一次的字符:
题目介绍:
给你一个只包含小写字母的字符串。请你判断是否存在只在字符串中出现过一次的字符。如果存在,则输出满足条件的字符中位置最靠前的那个。如果没有,输出 no
输入样例:
abceabcd
输出样例:
e
代码详解:
#include<bits/stdc++.h>
using namespace std;
int cnt[26]; //用于记录26个字母的出现次数
int main()
{
string s;
cin>>s;
for(int i=0;s[i];i++) cnt[s[i]-'a']++; //a变0,b变1,以此类推
for (int i = 0; s[i]; i ++ )
if (cnt[s[i] - 'a'] == 1)
{
cout << s[i] << endl;
return 0;
}
puts("no");
}
扩展:
上处是将字符转换成对应数字,若想将字符转换成字符,可见下面的题5《信息加密》
3、比较字符串大小:
题目介绍:
请写一个程序,实现对两个字符串进行忽略字母大小写的大小比较。
输入格式
输入为两行,每行一个字符串,共两个字符串。注意字符串中可能包含空格。
数据保证每个字符串的长度都不超过 80
输出格式
如果第一个字符串比第二个字符串小,输出一个字符 <。
如果第一个字符串比第二个字符串大,输出一个字符 >。
如果两个字符串相等,输出一个字符 =。
输入样例:
Hello
hello
输出样例:
=
代码详解:
#include<bits/stdc++.h>
using namespace std;
int main()
{
char a[100], b[100];
cin.getline(a,100);
cin.getline(b,100); //因为此处有回车,所以不能直接cin
for (int i = 0; a[i]; i ++ )
if (a[i] >= 'A' && a[i] <= 'Z')
a[i] += 32;
for (int i = 0; b[i]; i ++ )
if (b[i] >= 'A' && b[i] <= 'Z')
b[i] += 32;
int t = strcmp(a, b);
if (t == 0) puts("=");
else if (t < 0) puts("<");
else puts(">");
return 0;
}
加餐小灶:
一、cin:接收一个字符串,遇“空格”、“TAB”、“回车”就结束
例如:
#include <iostream>
using namespace std;
int main ()
{
char a[20];
cin>>a; //输入为jkljkl jkljkl
cout<<a<<endl; //输出为jkljkl
}
二、cin.getline():接收一个字符串,可以接收空格并输出
例如:
#include <iostream>
using namespace std;
int main ()
{
char m[20];
cin.getline(m,5); //输入为jkljkljkl
cout<<m<<endl; //输出为jklj(接收5个字符,但最后一个为'\0',所以输出4个)
}
延伸:
1、cin.getline()实际上有三个参数,cin.getline(接收字符串的变量,接收字符个数,结束字符)
2、当第三个参数省略时,系统默认为’\0’
3、如果将例子中cin.getline()改为cin.getline(m,5,‘a’);当输入jlkjkljkl时输出jklj,输入jkaljkljkl时,输出jk
三、getline:接收一个字符串,可以接收空格并输出,需包含“#include<string>”
例如:
#include<iostream>
#include<string>
using namespace std;
int main ()
{
string str;
getline(cin,str);
cout<<str<<endl;
}
4、去掉多余空格:
题目介绍:
输入一个字符串,字符串中可能包含多个连续的空格,请将多余的空格去掉,只留下一个空格。
输入格式
共一行,包含一个字符串。
输出格式
输出去掉多余空格后的字符串,占一行。
数据范围
输入字符串的长度不超过 200。保证输入字符串的开头和结尾没有空格。
输入样例:
Hello world.This is c language.
输出样例:
Hello world.This is c language.
代码详解:
#include<iostream>
using namespace std;
int main()
{
string s;
while(cin>>s) cout << s << ' ' ; //巧用上处加餐小灶中提及的“cin遇空格就停止”
return 0;
}
5、信息加密:
题目介绍:
现在给定一个字符串,对其进行加密处理。加密的规则如下:
字符串中的小写字母,a 加密为 b,b加密为 c,…,y 加密为 z,z 加密为 。
字符串中的大写字母,A 加密为 B,B 加密为 C,…,Y 加密为 Z,Z 加密为 A。
字符串中的其他字符,不作处理。请你输出加密后的字符串。
输入格式
共一行,包含一个字符串。注意字符串中可能包含空格。
输出格式
输出加密后的字符串。
数据范围
输入字符串的长度不超过 100
输入样例:
Hello! How are you!
输出样例:
Ifmmp! Ipx bsf zpv!
代码详解:
#include <iostream>
using namespace std;
int main()
{
string s;
getline(cin, s);
for (auto &c : s)
if (c >= 'a' && c <= 'z') c = (c - 'a' + 1) % 26 + 'a'; //减了'a'再加回去
else if (c >= 'A' && c <= 'Z') c = (c - 'A' + 1) % 26 + 'A'; //同理
cout << s << endl;
return 0;
}
6、输出字符串:
题目介绍:
给定一个字符串 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, b;
getline(cin, a);
for (int i = 0; i < a.size(); i ++ ) b += a[i] + a[(i + 1) % a.size()]; //与上题类似,巧用余数实现环形输入
cout << b << endl;
return 0;
}
7、单词替换:
题目介绍:
输入一个字符串,以回车结束(字符串长度不超过 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
代码详解:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string s, a, b;
getline(cin, s);
cin >> a >> b;
stringstream ssin(s); //流的输入输出
string str;
while (ssin >> str)
if (str == a) cout << b << ' ';
else cout << str << ' ';
return 0;
}
8、字符串中最长的连续出现的字符:
题目介绍:
求一个字符串中最长的连续出现的字符,输出该字符及其出现次数,字符串中无空白字符(空格、回车和 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 - i > cnt) cnt = j - i, c = str[i];
i = j - 1; //for每次完成循环体内容后会进行i++操作,如果不先j-1回去,则会跳过一个值
} //经典的双指针方法
cout << c << ' ' << cnt << endl;
}
return 0;
}
9、最长单词:
题目介绍:
一个以 . 结尾的简单英文句子,单词之间用空格分隔,没有缩写形式和其它特殊形式,求句子中的最长单词。
输入格式
输入一行字符串,表示这个简单英文句子,长度不超过 500。
输出格式
该句子中最长的单词。如果多于一个,则输出第一个。
输入样例:
I am a student of Peking University.
输出样例:
University
代码详解:
#include <iostream>
using namespace std;
int main()
{
string res, str;
while (cin >> str) //依然是利用cin的特性挨个输入
{
if (str.back() == '.') str.pop_back(); //去除'.',防止将其纳入单词长度的计算
if (str.size() > res.size()) res = str;
}
cout << res << endl;
return 0;
}
10、倒排单词:
题目介绍:
编写程序,读入一行英文(只包含字母和空格,单词间以单个空格分隔),将所有单词的顺序倒排并输出,依然以单个空格分隔。
输入格式
输入为一个字符串(字符串长度至多为 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;
}
11、字符串移位包含问题:
题目介绍:
对于一个字符串来说,定义一次循环移位操作为:将字符串的第一个字符移动到末尾形成新字符串。
给定两个字符串 s1和 s2,要求判定其中一个字符串是否是另一字符串通过若干次循环移位后的新字符串的子串。
例如 CDAA 是由 AABCD 两次移位后产生的新串 BCDAA 的子串,而 ABCD 与 ACBD 则不能通过多次移位来得到其中一个字符串是新串的子串。
输入格式
共一行,包含两个字符串,中间由单个空格隔开。
字符串只包含字母和数字,长度不超过 30。
输出格式
如果一个字符串是另一字符串通过若干次循环移位产生的新串的子串,则输出 true,否则输出 false。
输入样例:
AABCD CDAA
输出样例:
true
代码详解:
#include <iostream>
#include <algorithm>
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的用法
for (int j = 0; j + b.size() <= a.size(); j ++ )
{
int k = 0;
for (; k < b.size(); k ++ )
if (a[j + k] != b[k])
break;
if (k == b.size())
{
puts("true");
return 0;
}
}
}
puts("false");
return 0;
}
12、字符串乘方:
题目介绍:
给定两个字符串 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>
using namespace std;
int main()
{
string str;
while (cin >> str, str != ".")
{
int len = str.size();
for (int n = len; n; n -- )
if (len % n == 0)
{
int m = len / n;
string s = str.substr(0, m);
string r;
for (int i = 0; i < n; i ++ ) r += s; //拼接再组合,看是否与原来相等
if (r == str)
{
cout << n << endl;
break;
}
}
}
return 0;
}
解法二:
#include <iostream>
using namespace std;
int main() {
string a;
while(cin >> a, a!=".") { //注意这里该用双引号,因为是字符串类型
string b = a;
for(int i=0;a[i];i++) {
b = b.substr(1) + b[0]; //可以优化为每次移位距离都是能整除原串长度的
if(a == b) { //每次循环位移一位,与原串比较是否相等
cout << a.size() / (i+1) << endl; //根据贪心策略,长度除以最少位移距离即所求
break;
}
}
}
return 0;
}
13、字符串最大跨距:
题目介绍:
有三个字符串 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
代码详解
#include <iostream>
using namespace std;
int main() {
string a,b,c;
getline(cin,a,',');
getline(cin,b,',');
getline(cin,c);
int x,y;
x = a.find(b);
y = a.rfind(c);
if(x==-1 || y==-1 || x + b.size() > y) {
cout << -1;
return 0;
}
cout << y - x - b.size(); //之所以要减去b.size(),是因为样例中a与ab的位置相同,但答案长度不同,b的长度影响了最后长度
return 0;
}
加餐小灶:
find函数的用法:
(1)查找第一次出现的目标字符串:ans = s1.find(s2)。如果查找成功则输出查找到的第一个位置,否则返回-1
(2)查找从指定位置开始的第一次出现的目标字符串:ans = s1.find(s2, 2)
(3)rfind():反向查找字符串,即找到最后一个与子串匹配的位置
14、最长公共字符串后缀:
题目介绍;
给出若干个字符串,输出这些字符串的最长公共后缀。
输入格式
由若干组输入组成。每组输入的第一行是一个整数 N。
N为0时表示输入结束,否则后面会继续有 N行输入,每行是一个字符串(字符串内不含空白符)。
每个字符串的长度不超过 200。
输出格式
共一行,为 N个字符串的最长公共后缀(可能为空)。
数据范围
1≤N≤200
输入样例:
3
baba
aba
cba
2
aa
cc
2
aa
a
0
输出样例:
ba
a
代码详解:
#include <iostream>
using namespace std;
const int N = 200;
int n;
string str[N];
int main()
{
while (cin >> n, n)
{
int len = 1000;
for (int i = 0; i < n; i ++ )
{
cin >> str[i];
if (len > str[i].size()) len = str[i].size();
}
while (len) //枚举后缀长度(顶多是其中的最短字符串长度)
{
bool success = true;
for (int i = 1; i < n; i ++ )
{
bool is_same = true;
for (int j = 1; j <= len; j ++ )
if (str[0][str[0].size() - j] != str[i][str[i].size() - j])
{
is_same = false;
break;
}
if (!is_same)
{
success = false;
break;
}
}
if (success) break; //满足所有字符串的最长后缀相同
len -- ;
}
cout << str[0].substr(str[0].size() - len) << endl;
}
return 0;
}
总结:
“抬头望去,银河好像哗啦一声,向我的心坎上倾泻了下来”,希望我们都能在日夜研究的学习生活中,找到自己心中如此这般的星河。