【PTA数据结构 | C语言版】字符串匹配算法

发布于:2025-07-17 ⋅ 阅读:(17) ⋅ 点赞:(0)

本专栏持续输出数据结构题目集,欢迎订阅。

文章目录

题目

请编写程序,得到模式串 t 在主串 s 中首次出现的位置。

本题旨在测试各种不同的匹配算法在各种数据情况下的表现。各组测试数据特点如下:

  • 数据0:小规模字符串,测试基本正确性;
  • 数据1:随机数据,String 长度为 10^5,Pattern 长度为 10;
  • 数据2:随机数据,String 长度为 10^5,Pattern 长度为 10^2;
  • 数据3:随机数据,String 长度为 10^5,Pattern 长度为 10^3;
  • 数据4:随机数据,String 长度为 10^5,Pattern 长度为 10^4;
  • 数据5:String 长度为 10^6,Pattern 长度为 10^5;测试尾字符不匹配的情形;
  • 数据6:String 长度为 10^6,Pattern 长度为 10^5;测试首字符不匹配的情形。

输入格式:
输入先后给出主串 s 和模式串 t,每个非空字符串占一行,以回车结束(回车不算在字符串内)。

输出格式:
如果匹配成功,则输出 s 从 t 首次出现的位置开始的子串;否则输出 匹配失败。。

输入样例 1:
This is a simple test.
is

输出样例 1:
is is a simple test.

输入样例 2:
This is a test.
simple

输出样例 2:
匹配失败。

代码

#include <stdio.h>
const int cnt = 1000000;

// KMP算法的预处理函数:计算部分匹配表(next数组)
void build(char* p, int m, int next[]) {
    next[0] = -1;  // 初始化next数组
    int k = -1;    // 前缀长度
    
    // 构建next数组,长度为m-1
    for(int j = 0; j < m - 1; j++) {
        // 若字符不匹配,回溯到上一个可能的位置
        while(k >= 0 && p[j] != p[k])
            k = next[k];
        k++;
        next[j + 1] = k;  // 记录当前位置的最长公共前后缀长度
    }   
}

// KMP字符串匹配主函数
int kmp(int n, int m, char* s, char *p) {
    int i = 0;  // 主串指针
    int j = 0;  // 模式串指针
    int next[cnt];
    
    // 预处理模式串,构建next数组
    build(p, m, next);
    
    // 双指针遍历主串和模式串
    while(i < n && j < m) {
        // 当前字符匹配或需要从头开始匹配
        if(j == -1 || s[i] == p[j]) {
            i++;
            j++;
        } else {
            // 字符不匹配,利用next数组回退模式串指针
            j = next[j];
        }
    }
    
    // 匹配成功返回起始位置,否则返回-1
    return (j == m) ? i - m : -1;
}

int main() {
    char p[cnt]; // 模式串
    char s[cnt]; // 主串
    int n = 0;   // 主串长度
    int m = 0;   // 模式串长度
    
    // 读取主串(不包含换行符)
    while ((s[n] = getchar()) != '\n') {
        n++;
    }
    
    // 读取模式串(不包含换行符)
    while ((p[m] = getchar()) != '\n') {
        m++;
    }
 
    // 执行KMP匹配
    int q = kmp(n, m, s, p);
    
    // 输出匹配结果
    if (q != -1) {
        // 输出从匹配位置开始的子串
        for (int i = q; i < n; i++) {
            printf("%c", s[i]);
        }
        printf("\n");
    } else {
        printf("匹配失败。\n");
    }
 
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到