当前位置: 首页 > news >正文

《P3375 【模板】KMP》

题目描述

给出两个字符串 s1​ 和 s2​,若 s1​ 的区间 [l,r] 子串与 s2​ 完全相同,则称 s2​ 在 s1​ 中出现了,其出现位置为 l。
现在请你求出 s2​ 在 s1​ 中所有出现的位置。

定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t,满足 t 既是 s 的前缀,又是 s 的后缀。
对于 s2​,你还需要求出对于其每个前缀 s′ 的最长 border t′ 的长度。

输入格式

第一行为一个字符串,即为 s1​。
第二行为一个字符串,即为 s2​。

输出格式

首先输出若干行,每行一个整数,按从小到大的顺序输出 s2​ 在 s1​ 中出现的位置。
最后一行输出 ∣s2​∣ 个整数,第 i 个整数表示 s2​ 的长度为 i 的前缀的最长 border 长度。

输入输出样例

输入 #1复制

ABABABC
ABA

输出 #1复制

1
3
0 0 1 

说明/提示

样例 1 解释

对于 s2​ 长度为 3 的前缀 ABA,字符串 A 既是其后缀也是其前缀,且是最长的,因此最长 border 长度为 1。

数据规模与约定

本题采用多测试点捆绑测试,共有 3 个子任务

  • Subtask 1(30 points):∣s1​∣≤15,∣s2​∣≤5。
  • Subtask 2(40 points):∣s1​∣≤104,∣s2​∣≤102。
  • Subtask 3(30 points):无特殊约定。

对于全部的测试点,保证 1≤∣s1​∣,∣s2​∣≤106,s1​,s2​ 中均只含大写英文字母。

代码实现:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// 计算前缀函数(next数组)
vector<int> compute_prefix_function(const string& pattern) {
    int m = pattern.length();
    vector<int> next(m, 0);
    int len = 0;
    int i = 1;
    
    while (i < m) {
        if (pattern[i] == pattern[len]) {
            len++;
            next[i] = len;
            i++;
        } else {
            if (len != 0) {
                len = next[len - 1];
            } else {
                next[i] = 0;
                i++;
            }
        }
    }
    return next;
}

// KMP字符串匹配算法
vector<int> kmp_search(const string& text, const string& pattern, const vector<int>& next) {
    vector<int> positions;
    int n = text.length();
    int m = pattern.length();
    int i = 0;  // 文本的索引
    int j = 0;  // 模式的索引
    
    while (i < n) {
        if (pattern[j] == text[i]) {
            j++;
            i++;
        }
        
        if (j == m) {
            positions.push_back(i - j + 1);  // 存储出现位置(1-based)
            j = next[j - 1];
        } else if (i < n && pattern[j] != text[i]) {
            if (j != 0) {
                j = next[j - 1];
            } else {
                i++;
            }
        }
    }
    return positions;
}

int main() {
    string s1, s2;
    cin >> s1 >> s2;
    
    // 计算前缀函数
    vector<int> next = compute_prefix_function(s2);
    
    // 执行KMP搜索
    vector<int> positions = kmp_search(s1, s2, next);
    
    // 输出出现位置(使用传统迭代器方式)
    for (vector<int>::iterator it = positions.begin(); it != positions.end(); ++it) {
        cout << *it << endl;
    }
    
    // 输出前缀函数结果
    for (int i = 0; i < s2.length(); i++) {
        cout << next[i] << (i == s2.length() - 1 ? "\n" : " ");
    }
    
    return 0;
}

http://www.xdnf.cn/news/602479.html

相关文章:

  • 9大开源AI智能体概况
  • Python爬虫(34)Python爬虫高阶:动态页面处理与Playwright增强控制深度解析
  • c语言文件操作详解
  • 实验-设计一个应用系统(计算机组成原理)
  • Web攻防-SQL注入数据库类型用户权限架构分层符号干扰利用过程发现思路
  • Docker 与 Kubernetes 部署 RabbitMQ 集群(一)
  • 数据共享中的库表交换怎么做?
  • 【生成模型】【基础知识】CFG与CFG蒸馏
  • 深度解析:SQLynx 如何筑牢数据库安全防线​
  • 邻近标记技术(PL)在癌症研究中的应用
  • 动态规划中的 求“最长”、“最大收益”、“最多区间”、“最优策略” 双重 for + 状态转移
  • 视觉语言模型(Vision-Language Model, VLM)的简单介绍
  • 文章记单词 | 第105篇(六级)
  • Python、PyTorch、TensorFlow和飞桨(PaddlePaddle)的核心介绍及对比
  • Flutter遇到的问题
  • 安装 tensorflow-2.10.0 支持 gpu
  • 【Go-4】函数
  • Android Studio 开发环境兼容性检索(AGP / Gradle / Kotlin / JDK)
  • 音频AAC编码与RV1126的AENC模块的讲解
  • 什么是VR场景?VR与3D漫游到底有什么区别
  • [Windows] 格式工厂 FormatFactory v5.20.便携版 ——多功能媒体文件转换工具
  • Ansible快速入门指南
  • A服务器备份rabbitmq持久化目录到B服务器,不显示mq队列消息
  • 智警杯备赛--数据应用技术1
  • Spyglass:CDC官方Hands-on Training(三)
  • Oracle Apps R12——报表入门2:单表——报表开发流程
  • 常见的gittee开源项目推荐
  • 同为科技领军智能电源分配单元技术,助力物联网与计量高质量发展
  • 在项目中如何保证软件质量?
  • 基于SpringMVC的动态时钟设计