前言
洛谷【入门5】字符串 题单简介
计算机并不仅仅能够处理数学问题,还可以用来处理文字,比如写文章、处理代码、记录信息等等……如果需要将各种语句记录在计算机中,就要用到字符串或者字符数组。
我们已经在最开始的地方尝试输出过"I love Luogu" 的字符串,也介绍过单个字符和数字对应的 ASCII 编码。在这一章会介绍字符串的存储和处理的方法。同时也初步接触了 STL,这使得可以“站在前人的肩膀上”完成程序,简化编程的难度。
下面是亿点点广告…

以上题单的选题来自洛谷编写教材《深入浅出程序设计竞赛 - 基础篇》,并带有详细的教程和讲解,点击下方的图片了解该图书详情。【官方网店绝赞热卖中!】>>>
更有 kkksc03 站长亲自讲授的交互课,配套《深入浅出》使用,亲自在课堂中编写程序,在动手的过程中学习。【点击此处报名!】>>>
题目代码
P5733 【深基6.例1】自动修正
使用字符串的 upper 方法可以高效完成小写字母转大写操作。upper 可以转换字符串中的小写字母,其他字符保持原样。
代码
w = input()
print(w.upper())
P1914 小书童——凯撒密码
由于密码是小写字母,可以将每一位密码减去 a 的 ASCII 编码,这样就得到了该位密码在字母表中的位置(注意是从
0
0
0 开始),再加上
n
n
n,就能求出移动后的位置。移动后可能超出字母表,所以要对
26
26
26 取模。最后加回 a 的 ASCII 编码输出即可。
代码
#include <bits/stdc++.h>
using namespace std;
char m[100];
int n;
int main() {
scanf("%d%s", &n, m);
for (int i = 0; m[i] != '\0'; i++) printf("%c", (m[i] - 'a' + n) % 26 + 'a');
return 0;
}
P1125 [NOIP 2008 提高组] 笨小猴
给定一个字符串,判断这个字符串中出现次数最多的字母出现的次数和出现最少的字母(至少 1 1 1 次)的出现次数之差是否是质数。
直接用桶数组或者 map 记录次数,然后遍历字符串找出最大值和最小值,最后求差再判断质数并且按题目要求输出即可。
代码
#include <bits/stdc++.h>
using namespace std;
char s[100];
int c[26], a, b = 100;
bool f(int x) {
if (x < 2) return 0;
for (int i = 2; i * i <= x; i++) if (x % i == 0) return 0;
return 1;
}
int main() {
scanf("%s", s);
for (int i = 0; i < strlen(s); i++) c[s[i] - 'a']++;
for (int i = 0; i < 26; i++) if (c[i]) a = max(a, c[i]), b = min(b, c[i]);
f(a - b) ? printf("Lucky Word\n%d\n", a - b) : printf("No Answer\n0\n");
return 0;
}
P1957 口算练习题
一个个情况判断过去,用 switch 写一个分支。
其实可以将此段写成一个函数调用,会简洁很多。
to_string(a) + "+-*之一" + to_string(b) + "=" + to_string(a + b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
#include <bits/stdc++.h>
using namespace std;
int n, a, b, l, p, k;
string s, x;
bool i;
void w() {
for (l = 2; s[l] > 47 && s[l] <= '9'; l++) a = a * 10 + (s[l] - 48);
for (l++; s[l] > 47 && s[l] <= '9'; l++) b = b * 10 + (s[l] - 48);
}
void q() {
for (l = 0; s[l] > 47 && s[l] <= '9'; l++) a = a * 10 + (s[l] - 48);
for (l++; s[l] > 47 && s[l] <= '9'; l++) b = b * 10 + (s[l] - 48);
}
int main() {
scanf("%d\n", &n);
while (n--) {
getline(cin, s), x = "", i = a = b = 0;
switch (s[0]) {
case 'a': p = 0, i = 1; break;
case 'b': p = 1, i = 1; break;
case 'c': p = 2, i = 1; break;
}
switch (p) {
case 0:
if (i) w(), x = to_string(a) + "+" + to_string(b) + "=" + to_string(a + b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
else q(), x = to_string(a) + "+" + to_string(b) + "=" + to_string(a + b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
break;
case 1:
if (i) w(), x = to_string(a) + "-" + to_string(b) + "=" + to_string(a - b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
else q(), x = to_string(a) + "-" + to_string(b) + "=" + to_string(a - b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
break;
case 2:
if (i) w(), x = to_string(a) + "*" + to_string(b) + "=" + to_string(a * b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
else q(), x = to_string(a) + "*" + to_string(b) + "=" + to_string(a * b), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
break;
}
}
return 0;
}
代码
代码就变得十分简洁:
#include <bits/stdc++.h>
using namespace std;
int n, a, b, l, p, k;
string s, x;
bool i;
void w() {
for (l = 2; s[l] > 47 && s[l] <= '9'; l++) a = a * 10 + (s[l] - 48);
for (l++; s[l] > 47 && s[l] <= '9'; l++) b = b * 10 + (s[l] - 48);
}
void q() {
for (l = 0; s[l] > 47 && s[l] <= '9'; l++) a = a * 10 + (s[l] - 48);
for (l++; s[l] > 47 && s[l] <= '9'; l++) b = b * 10 + (s[l] - 48);
}
string D(int &P) {
return P < 3 ? P < 2 ? "+" : "-" : "*";
}
int F(int &P) {
return P < 3 ? P < 2 ? a + b : a - b : a * b;
}
void X(int P) {
x = to_string(a) + D(P) + to_string(b) + "=" + to_string(F(P)), cout << x, putchar('\n'), printf("%d", x.size()), putchar('\n');
}
int main() {
scanf("%d\n", &n);
while (n--) {
getline(cin, s), x = "", i = a = b = 0;
switch (s[0]) {
case 'a': p = 0, i = 1; break;
case 'b': p = 1, i = 1; break;
case 'c': p = 2, i = 1; break;
}
switch (p) {
case 0: i ? w() : q(), X(1); break;
case 1: i ? w() : q(), X(2); break;
case 2: i ? w() : q(), X(3); break;
}
}
return 0;
}
P5015 [NOIP 2018 普及组] 标题统计
众所周知,cin 不能读空格,所以,给刚入门的同学普及一个好东西 getline(cin, s)(其中 s 为要将读入的数据存入的字符串),这玩意儿能够一口气读取一整行的字符,空格也能一起读了,但不能读取换行符,所以这道题的就十分简单了。只需读取后,再遍历一遍,只要不为空格,就给统计,最后再将统计的答案输出即可。
代码
#include <bits/stdc++.h>
using namespace std;
string s;
int c;
int main() {
getline(cin, s);
for (int i = 0; i < s.size(); i++) if (s[i] != ' ') c++;
printf("%d\n", c);
return 0;
}
P5734 【深基6.例6】文字处理软件
这是一道很好的的字符串操作入门题,接下来将介绍如何使用字符数组构成的字符串来解决此题,适合使用 C/C++ 的读者。
库函数是相对高效的
相对于其他基本数据类型,字符串的存储和操作需要耗费大量空间和时间,但在某些情况下字符串的使用又是不可避免的,这推动字符串操作的相关库函数在大量底层优化后是相对高效的。
希望本篇题解能使读者更好的了解字符串相关库函数。
此篇使用到的库函数:
extern char strcat(char dest, const char src);
strcat函数将 s r c src src 串拼接到 d e s t dest dest 串之后。
extern char strstr(char str1, const char str2);
strstr函数在 s t r 1 str1 str1 串内查找 s t r 2 str2 str2 串的位置,如未找到,则返回NULL。
extern char strcpy(char dest, const char src);
strcpy函数将 s r c src src 串复制到 d e s t dest dest 串。
对于以下叙述(不包含代码部分),我们约定:
s t r str str 串表示原始串, i n in in 串表示读入串或暂存串。
对于操作 1 1 1:
需使用 strcat 函数,
- 将 i n in in 拼接到 s t r str str 串之后。
举例:
原始串:ILove
输入:1 Luogu
操作后:ILoveLuogu(存于
s
t
r
str
str 串)
对于操作 2 2 2:
需使用 strcpy 函数。
- 首先,将 s t r str str 串第 a + b a+b a+b 位及以后舍去;
- 接着,将 s t r str str 串第 a a a 位及以后复制到 i n in in 串中暂存;
- 最后,将 i n in in 串中暂存的内容复制回 s t r str str 串中。
举例:
原始串:ILoveLuoguMubuky
输入:2 5 5
-
第一步操作后:
ILoveLuogu(存于 s t r str str 串) -
第二步操作后:
Luogu(存于 i n in in 串) -
第三步操作后:
Luogu(存于 s t r str str 串)
对于操作 3 3 3:
需使用 strcat 函数。
- 首先,将 s t r str str 串第 a a a 位及以后的部分接到 i n in in 串后;
- 接着,将 i n in in 串接到 s t r str str 串第 a a a 位。
举例:
原始串:Luogu
输入:3 3 guGugu
-
第一步操作后:
guGugugu(存于 i n in in 串)Luo(存于str串) -
第二步操作后:
LuoguGugugu(存于str串)
对于操作 4 4 4:
需使用 strstr 函数。
查找 in 串在
s
t
r
str
str 串中的位置,若函数返回 NULL ,则如题输出
−
1
-1
−1,否则将函数返回的指针与字符串串首指针作差以获得其在字符串中的位置。
举例:
原始串:LuoguGugugu
输入:4 gu
输出:3
代码
#include <stdio.h>
#include <string.h>
char x[101], o[101];
char* l;
int q, t, a, b;
int main() {
scanf("%d\n%s", &q, x);
while (q--) {
scanf("%d", &t);
if (t == 1) scanf("%s", o), strcat(x, o), printf("%s\n", x);
else if (t == 2) scanf("%d %d", &a, &b), x[a + b] = '\0', strcpy(o, &x[a]), strcpy(x, o), printf("%s\n", x);
else if (t == 3) scanf("%d %s", &a, o), strcat(o, &x[a]), x[a] = '\0', strcat(x, o), printf("%s\n", x);
else scanf("%s", o), l = strstr(x, o), printf("%d\n", l != NULL ? (int) (l - x) : -1);
}
return 0;
}
P1308 [NOIP 2011 普及组] 统计单词数
就是找一个字符串的出现次数和位置(以类单词的形式查找,且不区分大小写)。
额,注意到这是普及题,大可以暴力。
复杂度分析:
1 ≤ 第一行单词长度 ≤ 10 , 1 ≤ 文章长度 ≤ 10 6 1≤ 第一行单词长度 ≤10,1≤ 文章长度 ≤10^6 1≤第一行单词长度≤10,1≤文章长度≤106。
很容易发现对于单词非常小,最最最多查找 10 7 10^7 107 次。
得,每次先读入一个字符串,然后一次次判断是否相同即可。
注意先将其变换为小写或大写字母再计算。
代码
#include <bits/stdc++.h>
using namespace std;
char s[10], t[1000000], h;
int n, m, c, p = -1;
int main() {
scanf("%s", s), n = strlen(s), scanf("%c", &h);
while (1) {
if (scanf("%c", &h) == EOF) break;
t[m++] = h;
}
for (int i = 0; i < n; i++) if (s[i] >= 'A' && s[i] <= 'Z') s[i] = s[i] - 'A' + 'a';
for (int i = 0; i < m; i++) if (t[i] >= 'A' && t[i] <= 'Z') t[i] = t[i] - 'A' + 'a';
for (int i = 0; i < m; i++) {
if (i + n > m) break;
bool d = 1;
for (int j = 0; j < n; j++)
if (t[i + j] != s[j]) {
d = 0;
break;
}
if ((i != 0 && t[i - 1] != ' ') || (i + n < m && t[i + n] != ' ')) d = 0;
if (d) {
c++;
if (p == -1) p = i;
}
}
if (c == 0) printf("-1\n");
else printf("%d %d\n", c, p);
return 0;
}
P1765 手机
这题很简单,只需要简单模拟。
首先要熟悉手机键盘,知道每一个字母在哪。
最后只需要遍历一下字符串,对于每一个字符判断要按几下,累加即可。
避雷:输入有空格。
代码
#include <bits/stdc++.h>
using namespace std;
char s;
int t;
int w(char c) {
if (c == ' ' || c == 'a' || c == 'd' || c == 'g' || c == 'j' || c == 'm' || c == 'p' || c == 't' || c == 'w') return 1;
if (c == 'b' || c == 'e' || c == 'h' || c == 'k' || c == 'n' || c == 'q' || c == 'u' || c == 'x') return 2;
if (c == 'c' || c == 'f' || c == 'i' || c == 'l' || c == 'o' || c == 'r' || c == 'v' || c == 'y') return 3;
if (c == 's' || c == 'z') return 4;
}
int main() {
while (scanf("%c", &s) == 1 && s != '\n') t += w(s);
printf("%d\n", t);
return 0;
}
P3741 小果的键盘
这个题无非只有四种排列情况:VK、KV、KK、VV。
其中,VK 是符合要求的,KK 和 VV 都能改一个字符成为 VK,只有 KV 不可以改。
先从头到尾跑一遍,把正确的 VK 都找出来。
再跑一遍找到一个 KK 或 VV 就停。
代码
#include <bits/stdc++.h>
using namespace std;
int v[101], s;
string a;
int main(){
scanf("%*d"), cin >> a;
for (int i = 0; i < a.size() - 1; i++) if (a[i] == 'V' && a[i + 1] == 'K') s++, v[i] = 1, v[i + 1] = 1;
for (int i = 0; i < a.size() - 1; i++) {
if (v[i] + v[i + 1] == 0 && a[i] == 'V' && a[i + 1] == 'V') {
s++;
break;
}
if (v[i] + v[i + 1] == 0 && a[i] == 'K' && a[i + 1] == 'K') {
s++;
break;
}
}
printf("%d", s);
return 0;
}
P1321 单词覆盖还原
还是挺水的。
注意到,boy 与 girl 的字符没有相同的,故而直接在字符串里判断,如果出现了对应字符,男或女的数量就
+
1
+1
+1。
需要注意的是,如果有连续的一段,是要算作一个的,比如 bo 就算做一个。
怎么解决呢?当然是向后顺延了。
代码
#include <bits/stdc++.h>
using namespace std;
string s;
int b, g;
int main(){
cin >> s;
for (int i = 0; i < s.size(); i++) {
if (s[i] == 'b' || s[i + 1] == 'o' || s[i + 2] == 'y') b++;
if (s[i] == 'g' || s[i + 1] == 'i' || s[i + 2] == 'r' || s[i + 3] == 'l') g++;
}
printf("%d\n%d\n", b, g);
return 0;
}
P1553 数字反转(升级版)
前置知识
推荐一些好用的 STL 函数:
find():判断某个字母是否在这个字符串中,如果不在,则返回npos。reverse():翻转这个字符串。substr():从某个字符串中截取子串。find_first_not_of():正向查找在原字符串中第一个与指定字符串(或字符)中的任一字符都不匹配的字符,返回它的位置如果不在,则返回npos。find_last_not_of():正向查找在原字符串中最后一个与指定字符串(或字符)中的任一字符都不匹配的字符,返回它的位置如果不在,则返回npos。
感兴趣的小伙伴还可以去搜 find_first_of() 和 find_last_of(),这里不讲。
题目分析
我们用字符串来解决。
首先需要判断输入是整数、小数、分数还是百分数,然后按照题目要求反转,最后用 find_first_not_of() 和 find_last_not_of() 去除前导
0
0
0 即可。
代码
#include <bits/stdc++.h>
using namespace std;
string s;
size_t f, g;
int main() {
cin >> s;
if (s[s.size() - 1] == '%') reverse(s.begin(), s.end() - 1);
else if ((f = s.find('.')) != string::npos) {
reverse(s.begin(), s.begin() + f), reverse(s.begin() + f + 1, s.end());
for (; *(s.end() - 1) == 48 && s.size() != f + 2; s.erase(s.end() - 1));
} else if ((f = s.find('/')) != string::npos) {
reverse(s.begin(), s.begin() + f), reverse(s.begin() + f + 1, s.end());
for (; *(s.begin() + f + 1) == 48; s.erase(s.begin() + f + 1));
}
else reverse(s.begin(), s.end());
for (; s[g] == 48 && s.size() - g != 1 && isdigit(s[g + 1]); ++g);
for (; s[g]; cout << s[g++]);
return 0;
}
P1603 斯诺登的密码
这道题目非常坑,尤其是 #3 和 #4。——摘自讨论区
我用了 printf("%.2d",a[i]); 就是不足
2
2
2 位前面补
0
0
0。
这题主要思路还是贪心,主要考点是字符串。
代码
#include<bits/stdc++.h>
using namespace std;
char V[30][10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty", "a", "both", "another", "first", "second", "third"}, s[100];
int E[30] = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 00, 21, 44, 69, 96, 25, 56, 89, 24, 61, 0, 1, 4, 1, 1, 4, 9};
unsigned long long int a[10], H, W;
int main() {
for (int i = 1; i < 7; i++) {
scanf("%s",&s);
for (int j = 1; j < 27; j++) if (!strcmp(s, V[j])) {
a[++H]=E[j];
break;
}
}
sort(a + 1, a + H + 1);
for (int i = 1; i <= H; i++) if (W) printf("%.2d",a[i]); else if (a[i]) printf("%d", a[i]), W = 1;
if (!W) putchar(48);
putchar('\n');
return 0;
}
P1200 [USACO1.1] 你的飞碟在这儿 Your Ride Is Here
对于每一个字符 c c c,可以用 c c c 减去 A A A 的 ASCII 值再加一得出它是第几个字母,最后相乘后取模判断相等即可。
代码
#include <bits/stdc++.h>
using namespace std;
char x[7], y[7];
int p = 1, q = 1, l, o;
int main() {
scanf("%s%s", x, y), l = strlen(x), o = strlen(y);
for (int i = 0; i < l; i++) p *= x[i] - 'A' + 1;
for (int i = 0; i < o; i++) q *= y[i] - 'A' + 1;
printf(p % 47 == q % 47 ? "GO\n" : "STAY\n");
return 0;
}
P1597 语句解析
未赋值的变量值为 0 0 0。循环解析每条语句,更新变量值,最后输出 a , b , c a,b,c a,b,c 的值。使用字符串处理,逐条解析语句,提取变量和值(数字或变量),更新对应变量。
代码
#include <bits/stdc++.h>
using namespace std;
char s[256];
int l, a, b, c, x;
int main(){
scanf("%s", s), l = strlen(s);
for (int i = 0; i < l / 5; i++) {
if (s[i * 5] == 'a') {
x = s[i * 5 + 3];
if (x == 'b') a = b;
else if (x == 'c') a = c;
else if (x != 'a') a = x - 48;
}
if (s[i * 5] == 'b') {
x = s[i * 5 + 3];
if (x == 'a') b = a;
else if (x == 'c') b = c;
else if (x != 'b') b = x - 48;
}
if (s[i * 5] == 'c') {
x = s[i * 5 + 3];
if (x == 'a') c = a;
else if (x == 'b') c = b;
else if (x != 'c') c = x - 48;
}
}
printf("%d %d %d\n", a, b, c);
return 0;
}
P1598 [USACO03FEB] 垂直柱状图 Vertical Histogram
这题最难的地方就在于输出,其他的都很简单。这里我们可以把输出的图形当作一个矩阵,求出出现字符最多的那一个字符的数量当作矩阵的行数,一行一行往下输出。如果当前字符在当前行可以输出就输出一个星号,否则输出一个空格。最后,把 A A A 到 Z Z Z 输出一遍即可。注意: Z Z Z 是一个特例,要单独输出,因为题目说了不许输出多余的空格。
代码
#include <bits/stdc++.h>
using namespace std;
string a;
map<char, int> W;
int m;
int main() {
for (int i = 1; i < 5; i++) {
getline(cin, a);
for (int i = 0; i < a.size(); i++) if (a[i] >= 'A' && a[i] <= 'Z') W[a[i]]++;
}
for (int i = 'A'; i <= 'Z'; i++) m = max(m, W[i]);
for (int i = m; i; i--) {
for (int j = 'A'; j < 'Z'; j++) printf(W[j] >= i ? "* " : " ");
if (W['Z'] >= i) putchar('*');
putchar('\n');
}
printf("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z");
return 0;
}
后记
创作不易,谢谢点赞 & 收藏!


7052

被折叠的 条评论
为什么被折叠?



