首页 > 编程语言 >算法基础课

算法基础课

时间:2022-12-12 18:00:30浏览次数:49  
标签:匹配 位置 ne 字符串 算法 基础课 回退 我们

给定一个字符串 SS,以及一个模式串 PP,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 PP 在字符串 SS 中多次作为子串出现。

求出模式串 PP 在字符串 SS 中所有出现的位置的起始下标。

输入格式

第一行输入整数 NN,表示字符串 PP 的长度。

第二行输入字符串 PP。

第三行输入整数 MM,表示字符串 SS 的长度。

第四行输入字符串 SS。

输出格式

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

数据范围

1≤N≤1051≤N≤105
1≤M≤1061≤M≤106

输入样例:

3
aba
5
ababa

输出样例:

0 2
难度:简单
时/空限制:1s / 256MB
总通过数:71523
总尝试数:139139
来源:模板题
算法标签

挑战模式

核心思路我们使用S表示我们的主串,P表示我们的模式串

  1. 首先我们联想字符串的暴力做法,我们使用i指针表示我们当前主串的位置,使用j指针表示我们当前模式串的位置。我们可以发现我们匹配的时候可以保持i指针不动,然后我们的j指针回退到P串的刚开始的位置就好了。但是这样我们会发现时间复杂度是很高的,也就是一个\(n^2\)的级别.
  2. 然后我们会想怎么进行优化呢。我们会发现一个很重要的点,就是其实我们每次没有必要回退到刚开始的位置。于是我们引入ne数组,首先我们得清楚他的定义:它表示的是P[1,i]中相等的前后缀的最长长度.接下来就是怎么去求这么一个数组。至于为什么不需要回退到刚开始的位置,可以看下我举的例子:
   1 2 3 4 5
S: a b a b a
P: a b a b c
我们可以看到当最后的位置不匹配的时候,也就是P[j+1]!=S[i].j=ne[j],也就是回退到2,然后P[j+1]再与S[i]比较,为什么可以这样呢,我们可以使用反证法。因为既然可以匹配到最后一个位置,那说明前面几个位置那必然是可以匹配的。所以必然是存在一段长度L是可以回退的。我们可以知道j回退到2其实与S中的字符串匹配的也就是以3为首的字符串开始。一定不要忘了我们的目的:我们是要从S中找到与P相匹配的位置.

下面先看一个基本的模拟样例:

我们可以知道ne数组的前后缀再匹配的时候。要么相等,那么这个值就会加1。不相等那我们是可以回退的:j=ne[j].这句话的意思是找到之前可以匹配的位置。我们需要知道求ne数组和我们最后的S和P的匹配是一样的,本质都是退而求其次的过程。所以代码都是大同小异的.下面我重点解释一下为什么每次都是j+1.因为我们需要到ne数组回退的位置前一个去匹配:

   1 2 3 4 5
S: a b a b a
P: a b a b c
就拿这个例子举例,当我们发现到i=5的时候j需要回退,要注意这个时候j是4,回退之后是2。很显然我们需要j+1=3这个位置继续去匹配。因为我们的S[34]已经等于了P[12].要注意我们的i还是5并没有回退哦。

知道这个了也就知道为什么j需要从0开始了,因为j+1正好指向P[1].还有一个初始值需要注意那就是ne[1]=0,因为只有一个字符他是没有前后缀的.所以我们的i从2开始枚举.

解释了ne数组怎么来的,自然也就知道了接下来的KMP匹配这是大同小异的.

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 6e6+10;
int m, n;
char s[N], p[N];
int ne[N];
int main()
{
	cin >> n >> p + 1;
		cin >> m>>s+1;
	ne[1] = 0;//初始化
	for (int i = 2, j = 0;i <= n;i++)//其实我们可以把i理解为后缀串也是没有问题的.
	{
		while (j && p[i] != p[j + 1])
			j = ne[j];
		if (p[i] == p[j + 1])
			j++;
		ne[i] = j;//这里可以理解为前后缀相等的最长长度确定了
	}
	for (int i = 1, j = 0;i <= m;i++)
	{
		while (j && s[i] != p[j + 1])
		{
			j = ne[j];
		}
		if (s[i] == p[j + 1])
		{
			j++;
		}
		if (j == n)
			cout << i - n  << " ";//因为我们需要找的是刚开始的位置,这已经超过n个单位的长度了,因为这下标是从0开始所以不需要加1
	}
}

标签:匹配,位置,ne,字符串,算法,基础课,回退,我们
From: https://www.cnblogs.com/xyh-hnust666/p/16976783.html

相关文章

  • C语言 (数据结构)在顺序表中用二分查找和冒泡排序算法
    main.c:#include<stdio.h>#include<stdlib.h>#include"SequenceList.h"intmain(){//创建顺序表和指针SequenceListSL,*P_SL;intchoice=0;......
  • 优先队列算法
    publicclassBinaryHeap<AnyTypeextendsComparable<?superAnyType>>{privatestaticfinalintDEFAULT_CAPACITY=10;privateintcurrentSize;privat......
  • 算法与数据结构实验四
    实验项目名称:实验四       一、 实验目的1)掌握图的邻接矩阵、邻接表存储结构表示及其创建算法2)掌握图的深度优先搜索遍历算法和图的广度优先搜索遍历算法;3)掌握图......
  • 算法与数据结构实验五 查找
    实验项目名称:实验五    查找  一、 实验目的1.掌握散列表的建立2.掌握散列查找算法的实现。二、 实验内容6-2线性探测法的查找函数试实现线性探测法的查找函......
  • 算法与数据结构实验六 内部排序
    实验项目名称:实验六    内部排序 一、 实验目的1.掌握插入排序的方法及效率分析2.掌握选择排序的方法及效率分析3.掌握交换排序的方法及效率分析4.掌握归并排序的......
  • 卡尔曼滤波算法-通俗理解
    简单来说,卡尔曼滤波器是一个“optimalrecursivedataprocessingalgorithm(最优化自回归数据处理算法)”。对于解决很大部分的问题,他是最优,效率最高甚至是最有用的。他的广......
  • TIANCHI天池-OGeek算法挑战赛-完整方案及代码(亚军)
    首先很幸运拿到TIANCHI天池-OGeek算法挑战赛大赛的亚军,同时非常感谢大佬队友的带飞,同时希望我的分享与总结能给大家带来些许帮助,并且一起交流学习。(作者:王贺,知乎:鱼遇雨欲语......
  • 每日算法之把数组排成最小的数
    JZ45把数组排成最小的数描述输入一个非负整数数组numbers,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组[3,32,321],则打印出这三......
  • 第一章算法概述总结
    代码规范类及其排版格式声明属性依次序是public:、protected:、private:。关键字public,protected,private不要缩进,声明的函数和变量缩进一个制表符。类声明前应加上注释,注......
  • 常见数据结构与算法的Python实现
    有人问我数据结构与算法怎么学?怎么用Python实现常见的数据结构算法?我找到一个github标星66.6k+的仓库,把各种常见算法用Python实现了,而且还有动图演示,非常值得推荐。(黄海广)仓......