字符串匹配

按大小写选项统一字符串后,用子串查找逐行筛选包含模式串的文本。

OJ: shumeng

题目 ID: CSP201409C

难度:入门

标签:字符串模拟

日期: 2026-07-31 16:21

形式化题目

给定模式串 SS、大小写敏感选项(0 不敏感,1 敏感)和多行文本,按输入顺序输出所有包含模式串的文本行。大小写不敏感时,同一字母的大小写视为相同字符。

思路

先看手写逐位置比较的暴力:

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:21
 * update_at: 2026-08-17 22:54
 */
// brute.cpp:小数据暴力解,枚举文本中的每个起点并逐字符比较。
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string pattern;
    int sensitive;
    int n;
    cin >> pattern >> sensitive >> n;

    for (int i = 0; i < n; i++) {
        string text;
        cin >> text;
        bool found = false;
        for (int start = 0; start + (int)pattern.size() <= (int)text.size(); start++) {
            bool same = true;
            for (int j = 0; j < (int)pattern.size(); j++) {
                char left = text[start + j];
                char right = pattern[j];
                if (!sensitive) {
                    if ('A' <= left && left <= 'Z') {
                        left = char(left - 'A' + 'a');
                    }
                    if ('A' <= right && right <= 'Z') {
                        right = char(right - 'A' + 'a');
                    }
                }
                if (left != right) {
                    same = false;
                    break;
                }
            }
            if (same) {
                found = true;
                break;
            }
        }
        if (found) {
            cout << text << '\n';
        }
    }

    return 0;
}

每一行独立判断,不需要保存全部文本。大小写不敏感时,先把模式串和当前文本都转换为小写,再调用 find() 判断模式串是否出现;大小写敏感时直接查找原字符串。输出时保留原始文本行。

处理流程

以样例为例,模式串 Hello,敏感选项为 1

文本行 包含 Hello? 输出
HelloWorld 输出
HiHiHelloHiHi 输出
GrepIsAGreatTool -
HELLO 否(大小写敏感) -
HELLOisNOTHello 输出

若把敏感选项改为 0,第 4 行 HELLO 转成小写 hello 后也能匹配,应当输出。

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:21
 * update_at: 2026-08-17 22:54
 */
#include <bits/stdc++.h>
using namespace std;

string lower_copy(string text) {
    for (int i = 0; i < (int)text.size(); i++) {
        if ('A' <= text[i] && text[i] <= 'Z') {
            text[i] = char(text[i] - 'A' + 'a');
        }
    }
    return text;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    string pattern;
    int sensitive;
    int n;
    cin >> pattern >> sensitive >> n;

    if (!sensitive) {
        pattern = lower_copy(pattern);
    }

    for (int i = 0; i < n; i++) {
        string text;
        cin >> text;
        string target = sensitive ? text : lower_copy(text);
        if (target.find(pattern) != string::npos) {
            cout << text << '\n';
        }
    }

    return 0;
}

复杂度

设文本行和模式串长度上界为 LL,共有 nn 行。标准库子串查找的最坏复杂度为 O(L2)O(L^2),总时间复杂度为 O(nL2)O(nL^2),额外空间复杂度为 O(L)O(L)

总结

字符串匹配题的关键是先明确比较规则,再统一输入的表示。匹配时使用规范化后的字符串,输出时使用原字符串,就能同时满足大小写选项和原行输出要求。