💻 C++ 字符串趣味特训营

这里有18道精选题目!
题目难度由浅入深,请先阅读代码,思考其中的逻辑,再点击按钮核对答案。加油!🎈

🔄 1、2014年第25题(字符串)
阅读程序
#include <iostream>
#include <string>
using namespace std;
int main()
{
    string st;
    int i, len;
    getline(cin, st);
    len = st.size();
    for (i = 0; i < len; i++)
        if (st[i] >= 'a' && st[i] <= 'z')
            st[i] = st[i] - 'a' + 'A';
    cout << st << endl;
    return 0;
}

输入:Hello, my name is Lostmonkey.

✅ 输出:HELLO, MY NAME IS LOSTMONKEY.

💡 解析思路:

  • st[i] >= 'a' && st[i] <= 'z':判断是否为小写字母。
  • st[i] - 'a' + 'A':将小写字母转换为对应的大写字母。
  • 程序将输入的所有小写字母转为大写,标点和空格不变。
⚖️ 2、2016年第26题(字符串比较)
阅读程序
#include <iostream>
using namespace std;
int main(){
    int i, length1, length2;
    string s1, s2;
    s1 = "I have a dream.";
    s2 = "I Have A Dream.";
    length1 = s1.size();
    length2 = s2.size();
    for (i = 0; i < length1; i++)
        if (s1[i] >= 'a' && s1[i] <= 'z')
            s1[i] -= 'a' - 'A';
    for (i = 0; i < length2; i++)
        if (s2[i] >= 'a' && s2[i] <= 'z')
            s2[i] -= 'a' - 'A';
    if (s1 == s2)
        cout << "=" << endl;
    else if (s1 > s2)
        cout << ">" << endl;
    else
        cout << "<" << endl;
    return 0;
}
✅ 输出:=

💡 解析思路:

  • 程序将 s1 和 s2 中的小写字母全部转为大写。
  • s1 变为 "I HAVE A DREAM."
  • s2 变为 "I HAVE A DREAM."
  • 两者相等,输出 "="。
🔐 3、2018年第18题(加密)
阅读程序
#include <stdio.h>
char st[100];
int main() {
    scanf("%s", st);
    for (int i = 0; st[i]; ++i) {
        if ('A' <= st[i] && st[i] <= 'Z')
            st[i] += 1;
    }
    printf("%s\n", st);
    return 0;
}

输入:QuanGuoLianSai

✅ 输出:RuanHuoMianTai

💡 解析思路:

  • 只对大写字母 ASCII码 + 1(即变成下一个字母),小写字母不变。
  • Q->R, G->H, L->M, S->T。
  • 其余小写字母保持原样。
🔢 4、2008年第9题(非空字串数量)
选择题

设字符串 S="Olympic",S 的非空子串的数目是( )。

  • A. 28
  • B. 29
  • C. 16
  • D. 17
✅ 正确答案:A

💡 解析思路:

  • 公式: 长度为 n 的字符串(无重复字符),非空子串数 = n(n+1)/2。
  • 计算: "Olympic" 长度 n=7。
  • 结果 = 7 × 8 / 2 = 28。
5、2016年第10题(概念)
单选题

以下关于字符串的判定语句中正确的是()。

  • A. 字符串是一种特殊的线性表
  • B. 串的长度必须大于零
  • C. 字符串不可以用数组来表示
  • D. 空格字符组成的串就是空串
✅ 正确答案:A

💡 解析思路:

  • A 对:字符串是元素仅为字符的线性表。
  • B 错:空串 "" 长度为0,是合法的。
  • D 错:空格组成的串 " " 长度为1,不是空串。
🔢 6、2017年第14题(子串数量)
单选题

若串 S="copyright",其子串的个数是( )。

  • A. 72
  • B. 45
  • C. 46
  • D. 36
✅ 正确答案:C

💡 解析思路:

  • "copyright" 长度为9,无重复字符。
  • 子串公式:n(n+1)/2 + 1 (加1是因为通常包含空串)。
  • 9×10/2 + 1 = 45 + 1 = 46。
📱 7、2011年第24题(手机键盘)
阅读程序
#include<iostream>
#include<string>
using namespace std;
int main(){
    string map = "2223334445556667778889999";
    string tel;
    int i;
    cin>>tel;
    for(i=0;i<tel.length();i++)
       if((tel[i]>='0') && (tel[i]<='9') )
           cout<<tel[i];
       else if( (tel[i]>='A') && (tel[i]<='Z'))
           cout<<map[tel[i]-'A'];
    cout<<endl;
    return 0;
}

输入:CCF-NOIP-2011

✅ 输出:22366472011

💡 解析思路:

  • 根据 map 字符串,ABC->2, DEF->3, ..., NO->6, PQRS->7, TUV->8, WXYZ->9。
  • CCF -> 223。
  • 连字符 '-' 被忽略。
  • NOIP -> 6647。
  • 2011 保持原样。
📖 8、2010年第25题(找最大字符)
阅读程序
#include <iostream>
#include <string>
using namespace std;
int main(){
    string s;
    char m1, m2;
    int i;
    getline(cin, s);
    m1 = ' ';
    m2 = ' ';
    for (i = 0; i < s.length(); i++)
        if (s[i] > m1) {
            m2 = m1;
            m1 = s[i];
        }
        else if (s[i] > m2)
            m2 = s[i];
    cout << int(m1) << ' ' << int(m2) << endl;
    return 0;
}

输入:Expo 2010 Shanghai China
提示:'a'=97, 'A'=65, '0'=48, 空格=32

✅ 输出:120 112

💡 解析思路:

  • 程序是在找字符串中 ASCII 码最大第二大的字符。
  • 在 "Expo 2010 Shanghai China" 中:
    • 最大的字符是小写 'x' (ASCII 120)。
    • 第二大的字符是小写 'p' (ASCII 112)。
    • 注意:小写字母 ASCII 均大于大写字母。
🔍 9、2017年第23题(唯一字符)
阅读程序
#include<iostream>
using namespace std;
int main()
{
    int t[256];
    string s;
    int i;
    cin >> s;
    for (i = 0; i < 256; i++)
        t[i] = 0;
    for (i = 0; i < s.length(); i++)
        t[s[i]]++; // 统计次数
    for (i = 0; i < s.length(); i++)
        if (t[s[i]] == 1) // 找第一个次数为1的
        {
            cout << s[i] << endl;
            return 0;
        }
    cout << "no" << endl;
    return 0;
}

输入:xyzxyw

✅ 输出:z

💡 解析思路:

  • 首先统计词频:x(2), y(2), z(1), w(1)。
  • 然后按字符串顺序再次遍历:
    • 第1个字符 x,出现2次,跳过。
    • 第2个字符 y,出现2次,跳过。
    • 第3个字符 z,出现1次,输出 z 并结束
🔢 10、2012年第19题(非空子串数量)
选择题

字符 AAABBBCCC 共有( )个不同的非空子串。

  • A. 3
  • B. 12
  • C. 36
  • D. 45
✅ 正确答案:C

💡 解析思路:

  • 分段统计:
    • AAA段:A, AA, AAA (3个)
    • BBB段:B, BB, BBB (3个)
    • CCC段:C, CC, CCC (3个)
  • 跨段组合:
    • AB交界:3个A × 3个B = 9个 (如 AAB, ABBB等)
    • BC交界:3个B × 3个C = 9个
    • ABC全跨:3个A × 3个C = 9个 (如 AAABBBCC)
  • 总计: 3+3+3 + 9+9+9 = 36。
🧩 11、2022年第14题(子串)
单选题

字符串 abcab 有( )个内容互不相同的子串。

  • A. 12
  • B. 13
  • C. 14
  • D. 15
✅ 正确答案:B

💡 解析思路:

  • 长度1:a, b, c (3个)
  • 长度2:ab, bc, ca (3个, 最后的ab重复)
  • 长度3:abc, bca, cab (3个)
  • 长度4:abca, bcab (2个)
  • 长度5:abcab (1个)
  • 共 3+3+3+2+1 = 12个。
  • 注意: 许多题库标准答案选 B(13),这通常是加上了空串。本页面遵循原题参考答案 B。
🐭 12、2018年第6题(键盘小老鼠)
单选题

循环按键序列:CapsLock, A, S, D, F。屏幕上输出的第 81 个字符是?(初始小写)

  • A. A
  • B. S
  • C. D
  • D. a
✅ 正确答案:A

💡 解析思路:

  • 一组循环5个键:[Caps, A, S, D, F],但只输出4个字母。
  • 81 / 4 = 20 ... 1。说明经过了20轮完整输出,正在第21轮的第1个字。
  • 大小写状态:
    • 第1轮:Caps按了一次 -> 大写 (输出A...)
    • 第2轮:Caps又按一次 -> 小写 (输出a...)
    • 奇数轮大写,偶数轮小写。
  • 第21轮是奇数轮 -> 大写。第1个字母是 A。
🔄 13、2008年第27题(字符串替换)
完善程序
#include <iostream>
#include <string.h>
char change[26], str[5000];
using namespace std;
void CheckChangeRule() {
    int i;
    for (i = 0; i < 26; i++) {
        if (【①】)
            change[i] -= 'A' - 'a';
    }
}
void ChangeString() {
    int i;
    for (i = 0; i < strlen(str); i++) {
        if (【②】)
            str[i] = change[str[i] - 'A'] - 'a' + 'A';
        else
            【③】;
    }
}
int main() {
    cin >> str >> change;
    CheckChangeRule();
    【④】;
    cout << str << endl;
    return 0;
}
✅ 答案:
① change[i] >= 'A' && change[i] <= 'Z'
② str[i] >= 'A' && str[i] <= 'Z'
③ str[i] = change[str[i] - 'a']
④ ChangeString()

💡 解析思路:

  • ①:把映射规则串 change 统一转成小写。
  • ②:判断原字符串字符是否为大写。
  • ③:如果是小写,直接从 change 数组取对应字符替换。
  • ④:调用替换函数。
🗑️ 14、2014年第27题(删除数字)
完善程序
#include <iostream>
using namespace std;
int delnum( char *s )
{
    int i, j;
    j = 0;
    for ( i = 0; s[i] != '\0'; i++ )
        if ( s[i] < '0' 【①】 s[i] > '9' )
        {
            s[j] = s[i];
            【②】;
        }
    return(【③】);
}
// main 中: cout << 【④】;
✅ 答案:① ||   ② j++   ③ j   ④ s[i]

💡 解析思路:

  • ①:保留非数字字符,即小于0 或者 大于9。使用 ||
  • ②:每保存一个有效字符,新下标 j 就要后移,j++
  • ③:函数返回新字符串的长度,即 j
📘 15、2007年第27题(字符串逆序)
完善程序

下面的程序的功能是输入若干行字符串,每输入一行,就按逆序输出该行,最后键入 -1 终止程序。请将程序补充完整。

#include <iostream.h>
#include <string.h>
int maxline = 200, kz;
int reverse( char s[] )
{
    int i, j, t;
    // i从前往后,j从后往前
    for ( i = 0, j = strlen( s ) - 1; i < j; 【①】, 【②】 )
    {
        t = s[i]; s[i] = s[j]; s[j] = t;
    }
    return(0);
}
int main()
{
    char line[100];
    cout << "continue? -1 for end." << endl;
    cin >> kz;
    while(【③】)
    {
        cin >> line;
        【④】;
        cout << line << endl;
        cout << "continue ? -1 for end." << endl;
        cin >> kz;
    }
}
✅ 答案:① i++   ② j--   ③ kz != -1   ④ reverse(line)

💡 解析思路:

  • reverse 函数: 双指针法。i 从头(0)开始增加,j 从尾(strlen-1)开始减少,当 i < j 时交换。所以①填 i++,②填 j--
  • main 函数:
    • ③ 题目要求输入 -1 终止,所以循环条件是 kz != -1
    • ④ 输入字符串后需要逆序,所以调用 reverse(line)
🔁 16、2012年第26题(循环位移)
阅读程序

找出字符串循环位移中字典序最小的一个。

char get(int i) {
    if (i < n) return s[i];
    else return s[i - n];
}
// main 部分逻辑
// 遍历所有可能的起始点 i,找到字典序最小的串
// if (get(i + j) < get(ans + j)) ans = i;

输入:CBBADADA

✅ 输出:ACBBADAD

💡 解析思路:

  • 原串 CBBADADA。
  • 我们需要把字符串切开并把前面部分放到后面,使得新串字典序最小。
  • 最小的字符是 'A'。观察 'A' 出现的位置。
  • 以倒数第二个 'A' 开头时:ACBBADAD。这是最小的组合。
🐛 17、2007年第26题(字符串展开)
阅读程序
#include "ctype.h"
#include "stdio.h"
void expand( char s1[], char s2[] )
{
    int i, j, a, b, c;
    j = 0;
    for ( i = 0; (c = s1[i]) != '\0'; i++ )
        if ( c == '-' )
    {
        a = s1[i - 1]; b = s1[i + 1];
        if ( isalpha( a ) && isalpha( b ) || isdigit( a ) && isdigit( b ) )
        {
            j--; // 回退,覆盖掉减号前面的字符
            do
                s2[j++] = a++;
            while ( tolower( a ) < tolower( s1[i + 1] ) );
        }
        else s2[j++] = c;
    }else s2[j++] = c;
    s2[j] = '\0';
}
// 假设 main 输入: wer2345d-h454-82qqq

输入:wer2345d-h454-82qqq

✅ 输出:wer2345defgh45456782qqq

💡 解析思路:

  • 程序将 char-charnum-num 展开。
  • d-h 展开为 defgh。
  • 4-8 展开为 45678。
  • 注意代码中的 j--,它把减号前面已经输出的那个字符重写了一遍,作为展开的起点。
🧠 18、2023年第17题(综合逻辑)
综合题
int f(string x, string y) {
    // 动态规划求最长公共子序列(LCS)长度
    // ... v[i][j] = max(...) ...
    return v[m][n];
}
bool g(string x, string y) {
    if (x.size() != y.size()) return false;
    return f(x + x, y) == y.size();
}
// main: cin >> x >> y; cout << g(x,y);

判断:

  1. f 函数返回值 <= min(n, m)。( )
  2. f 函数返回值等于最长公共子串长度。( )
  3. 若x与y相同,g返回true。( )

单选:

  1. 若把 v[m][n] 改为 v[n][m],程序会( )。A.正常 B.输出变 C.编译错 D.崩溃
  2. 输入 csp-j p-jcs,输出( )。A. 0   B. 1
✅ 答案:1.对 2.错 3.对 4.D 5.B

💡 解析思路:

  • 1. LCS长度肯定不超过两个字符串中较短的那个。
  • 2. LCS是子序列(不连续),不是子串(连续)。
  • 3. g函数判断循环同构。相同字符串肯定是循环同构。
  • 4. 数组定义是 v(m+1, n+1),访问 v[n][m] 可能会越界导致崩溃。
  • 5. "csp-j" 和 "p-jcs" 互为循环位移,输出 1。