Java/C++---KMP字符串匹配(每日一道算法2022.8.9)

题目
给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。
模式串 P 在字符串 S 中多次作为子串出现。
求出模式串 P 在字符串 S 中所有出现的位置的起始下标。

输入格式
第一行输入整数 N,表示字符串 P 的长度。
第二行输入字符串 P。
第三行输入整数 M,表示字符串 S 的长度。
第四行输入字符串 S。

输出格式
共一行,输出所有出现位置的起始下标(下标从 0 开始计数),整数之间用空格隔开。

数据范围
1≤N≤10e5
1≤M≤10e6

输入:
3
aba
5
ababa
输出:
0 2

Java:

public class kmp {
    //初始化
    public static int N = 1000010;
    public static char[] p = new char[N], s = new char[N];
    public static int[] ne = new int[N];

    public static void main(String[] args) throws IOException {
        //创建输出和输入流,防止数据过大超时
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

        //导入p和s数组的数据, 注意,i初始为1,所以要用<=
        int n = Integer.parseInt(in.readLine());
        String p_data = in.readLine();
        for (int i = 1; i<=n; i++) {p[i] = p_data.charAt(i-1);}

        int m = Integer.parseInt(in.readLine());
        String s_data = in.readLine();
        for (int i = 1; i<=m; i++) {s[i] = s_data.charAt(i-1);}

        //构造next数组,也就是前缀下标数组,i从2开始是因为第一位和第一位比较永远是0,可以省略
        //其实就相当于拿到前缀下标
        for (int i = 2, j = 0; i<=n; i++) {
            while (j > 0 && p[i] != p[j+1]) {j = ne[j];}
            if (p[i] == p[j+1]) {j++;}
            ne[i] = j;
        }

        //kmp判断
        //i指针为s,j指针为p
        for (int i = 1, j = 0; i<=m; i++) {
            //当j大于0且两个指针指向的值不相等时,将j赋值为ne[j]
            while (j > 0 && s[i] != p[j+1]) {j = ne[j];}
            //如果相等,那么就将j指针后移
            if (s[i] == p[j+1]) {j++;}
            //如果j等于n了,也就是j等于我们要找的字串长度了,输出其开头下标, 然后再把j赋值为ne[j]
            if (j == n) {
                out.write(i-n + " ");
                j = ne[j];
            }
        }

        //最后刷新输出
        out.flush();
    }
}

C++:

#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100010, M = 1000010;
int n, m;
char p[N], s[M];
int ne[N];

int main() {
    cin >> n >> (p+1) >> m >> (s+1);

    //ne
    for (int i = 2, j = 0; i<=n; i++) {
        while (j != 0 && p[i] != p[j+1]) j = ne[j];
        if (p[i] == p[j+1]) j++;
        ne[i] = j;
    }

    //kmp
    for (int i = 1, j = 0; i<=m; i++) {
        while (j != 0 && s[i] != p[j+1]) j = ne[j];
        if (s[i] == p[j+1]) j++;
        if (j == n) {
            cout << i-n << " ";
            j = ne[j];
        }
    }

    return 0;
}

kmp动画讲解以及next数组解释链接:kmp动画
不是我做的视频哈,真的解释的很清晰,推荐看。

今天又是三小时大战,人晕了,当我看到40分钟的课的时候我就意识到大的要来了呜呜呜
kmp算法果然无情(

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值