KMP算法的应用
设有两个串p和q,求q在p中首次出现的位置的运算称作

设有两个串p和q,求q在p中首次出现的位置的运算称作
首次出现位置的搜索:寻找q在p中的位置
在字符串匹配中,寻找q在p中首次出现的位置称作字符串搜索。
它的应用广泛,如从文本中检索特定模式、分词、重复字符串检测、字母表达式等等。
这里总结下常见的几种字符串搜索:
1. 暴力匹配:暴力匹配具有简单思想,即依次比较p串和q串两个字符串的每个字符,当发现不匹配时就继续寻找下一个字符串。
它最大的特点就是有效率低和易于实现,它的时间复杂度是O(m*n),其中m 为主串(p)的长度,n为模式串(q)的长度。
2. KMP算法:KMP算法的思想是从头开始,在p串中搜索q串,当发现不匹配的字符时,在q串中找出匹配子串,并跳转至下一个位置继续搜索。
KMP算法的时间复杂度略高于暴力匹配,但具有效率高和一定空间占用的优点,它的时间复杂度为O(m+n)。
3. BM算法:BM算法也是在字符串p中搜索q串,在发现不匹配的字符时,它跳转至模式串q的尾端的字符,继续搜索。
BM算法的时间
复杂度低于KMP算法,一般为O(m/n),同时也不需要额外的空间,实现起来也比较简单,是一种常见的字符串搜索算法。
总结起来,要求q在p中首次出现的位置的运算,可以选择暴力匹配、KMP算法和BM算法中的一种进行实现。
根据自身情况进行选择即可。
KMP算法(原创)PPT教学课件

? 这时如何求next[j+1]呢
2020/12/10
11
转化法
式1的结论可这样描述:何时的k使得
pk=pj,就用此时的k代入式1。
而现在的k是pk!=pj,因此必须要换成另外 一个“k”,并设它为k2,以使得pk2=pj。
问题又出来了: k2如何得来?
如图: 0 j-k+1
j
P’
2/10
2
(2) Brute-Force算法的实现
int String::Find Substr(const String& t, int start)const {
int i = start, j = 0, v; while(i < size && j < t.size) {
if(str[i] == t.str[j]) {i++;j++;} else {i = i-j+1;j = 0;} } if(j >= t.size-1) v = i-t.size+1; else v = -1; return v; }
由(1)(2)两式便可得:
‘p0p1……pk-1’= ‘pj-kpj-k+1……pj-1’ (3) (3)式的结论可如下描述:
在模式p中,前k个字符与第j个字符之前 的k个字符相同。
2020/12/10
7
设next[j]表示:当模式中第j个字符与正 文中相应字符“失配”时,在模式中重 新和正文中该字符进行比较的字符的位 置。
利用next数组进行模式匹配示例:
2020/12/10
9
如何预先求得next数组值
首先要明确一点: next数组的求值只与 模式p有关,而与具体的正文s无关。
如何应用分治算法求解问题

如何应用分治算法求解问题分治算法,英文名为Divide and Conquer Algorithm,是一种高效的算法设计策略,在计算机科学中有着广泛的应用。
该算法将一个大问题分解成多个小问题,各自独立地解决,再将结果合并起来得到最终结果。
在本文中,我们将阐述如何应用分治算法求解问题,并通过几个实例来具体说明该算法的应用。
一、分治算法的原理分治算法的核心思想是将一个大问题分解成若干个小问题来解决,然后将这些小问题的解组合起来生成大问题的解。
其具体步骤如下:1. 分解:将原问题划分成若干个规模较小的子问题。
2. 解决:递归地解决每个子问题。
如果子问题足够小,则直接求解。
3. 合并:将所有子问题的解合并成原问题的解。
分治算法的主要优点在于它可以有效地缩小问题规模,从而缩短整个算法的执行时间。
另外,该算法天然适用于并行计算,因为每个子问题都是独立求解的。
二、分治算法的应用分治算法在各种领域都有广泛应用,包括数学、自然科学、计算机科学等。
以计算机科学领域为例,分治算法常常用于解决以下类型的问题:1. 排序问题2. 查找问题3. 字符串匹配问题4. 最大子序列和问题5. 矩阵乘法问题6. 图形问题下面我们将一一讲解这些问题的分治算法实现。
1. 排序问题排序问题是在一组数据中将其按指定规律进行排列的问题。
在计算机科学中,排序算法是十分重要的一类算法。
其中,分治算法由于其高效性和可并行性被广泛应用。
常用的分治排序算法包括归并排序和快速排序。
归并排序的基本思想是将待排序元素以中心点为界分成两个序列,对每个序列进行排序,然后将两个序列合并成一个有序序列;而快速排序则利用了分割的思想,通过每次选取一个元素作为“轴点”,将数组分成小于轴点和大于轴点的两部分,对这两部分分别进行快速排序。
2. 查找问题查找问题是在一组数据中寻找某个元素的问题。
分治算法在查找问题中的应用主要体现在二分查找中。
在二分查找中,我们首先将已排序的数组分成两半,在其中一半中查找目标值。
kmp算法原理

kmp算法原理KMP算法(Knuth-Morris-Pratt算法)是一种用于快速搜索字符串中某个模式字符串出现位置的算法,由Knuth, Morris 和 Pratt于1977年提出。
KMP算法的工作方式如下:首先,给定一个主串S和一个模式串P,KMP算法的第一步就是先构造一个新的模式串P,其中的每一项存储着P中每一个字符前面由不同字符串组成的最长前缀和最长后缀相同的子串。
接着,在S中寻找P,它会从S的第一个字符开始,如果匹配上,就继续比较下一个字符,如果不匹配上,就根据P中相应位置上保存的信息跳到特定位置,接着再开始比较,如此不断循环下去,直到从S中找到P为止。
KMP算法的思路特别巧妙,比较效率很高,它的复杂度为O(m+n),其中m为主串的长度,n为模式串的长度。
它取代了以前的暴力搜索算法,极大地提高了程序的性能。
KMP算法的实现过程如下:(1)首先确定模式串P的每一个字符,构造模式串P的next数组:next[i]存储P中第i个字符之前最长相同前缀和后缀的长度(P中第i个字符之前最长相同前缀和后缀不包括第i个字符);(2)接着从S中的第一个字符开始比较P中的每一个字符,如果字符不匹配,则采用next数组中保存的信息跳到特定位置,而不是暴力比较,以此不断循环,直到从S中找到P为止。
KMP算法是由Don Knuth, Vaughan Pratt和James Morris在1977年提出的。
它的思想是利用之前遍历过的P的信息,跳过暴力比较,可以把字符串搜索时间从O(m×n)降低到O(m+n)。
KMP算法在很多领域有着重要的应用,如文本编辑,模式匹配,编译器设计与多项式字符串匹配等等,都是不可或缺的。
一种改进的KMP算法在不良网站信息过滤中的应用

一种改进的KMP算法在不良网站信息过滤中的应用作者:党红云蒋品群何婷婷来源:《现代电子技术》2012年第01期摘要:针对网络信息过滤的特点和现实中人们对网络信息纯净度的要求,提出了一种基于KMP字符串匹配算法,对不良网站信息进行过滤和相应的性能测试。
在测试环境下,对100组非法网站进行过滤,得出对不良信息过滤查准率达到95%,查全率达到98%,通过对测试数据的分析和网络吞吐量的测试结果表明,该方案所设计的系统性能基本能够满足实际需要。
关键词:信息过滤; KMP算法;模式匹配; 网络吞吐量中图分类号:TN919.1-34; TP311文献标识码:A文章编号:1004-373X(2012)01-0110-03Application of an improved KMP algorithm in bad website information filteringDANG Hong-yun, JIANG Pin-qun, HE Ting-(College of Electronic Engineering, Guangxi Normal University, Guilin 541004, China)Abstract:According to the characteristics of network information filtering and people′s requirem ent on the degree of purity of network information in reality, a KMP (Kunth-Morris-Pratt)-based string matching algorithm is introduced to filter the negative website information and test the corresponding performance. In the test environment, 100 groups of illegal websites were filtered. It is concluded thatthe filtering precision ratio on bad information has been reached 95% and recall ratio has been reached 98%. The analysis to the test data and the test results of network throughput show that the system performance designed by this scheme can basically meet the practical need.Keywords: information filtering; KMP algorithm; pattern match; network throughput收稿日期:2011-09-100 引言随着网络的日益普及和网络信息总量的激增,当人们正享受网络技术带给我们美好生活的同时,也使某些不法分子通过网络传送一些不健康的非法信息,因此,建立一种积极主动的信息安全过滤系统已成为网络安全领域中研究的热点。
KMP算法以及优化(代码分析以及求解next数组和nextval数组)

KMP算法以及优化(代码分析以及求解next数组和nextval数组)KMP算法以及优化(代码分析以及求解next数组和nextval数组)来了,数据结构及算法的内容来了,这才是我们的专攻,前⾯写的都是开胃⼩菜,本篇⽂章,侧重考研408⽅向,所以保证了你只要看懂了,题⼀定会做,难道这样思想还会不会么?如果只想看next数组以及nextval数组的求解可以直接跳到相应部分,思想总结的很⼲~~⽹上的next数组版本解惑先总结⼀下,⼀般KMP算法的next数组结果有两个版本,我们需要知道为什么会存在这种问题,其实就是前缀和后缀没有匹配的时候next数组为0还是为1,两个版本当然都是对的了,如果next数组为0是的版本,那么对于前缀和后缀的最⼤匹配长度只需要值+1就跟next数组是1的版本⼀样了,其实是因为他们的源代码不⼀样,或者对于模式串的第⼀个下标理解为0或者1,总之这个问题不⽤纠结,懂原理就⾏~~那么此处,我们假定前缀和后缀的最⼤匹配长度为0时,next数组值为1的版本,考研⼀般都是⽤这个版本(如果为0版本,所有的内容-1即可,如你算出next[5]=6,那么-1版本的next[5]就为5,反之亦然)~~其实上⾯的话总结就是⼀句话next[1]=0,j(模式串)数组的第⼀位下标为1,同时,前缀和后缀的最⼤匹配长度+1即为next数组的值,j所代表的的是序号的意思408反⼈类,⼀般数组第⼀位下标为1,关于书本上前⾯链表的学习⼤家就应该有⽬共睹了,书本上好多数组的第⼀位下标为了⽅便我们理解下标为1,想法这样我们更不好理解了,很反⼈类,所以这⾥给出next[1]=0,前缀和后缀的最⼤匹配长度+1的版本讲解前⾔以及问题引出我们先要知道,KMP算法是⽤于字符串匹配的~~例如:⼀个主串"abababcdef"我们想要知道在其中是否包括⼀个模式串"ababc"初代的解决⽅法是,朴素模式匹配算法,也就是我们主串和模式串对⽐,不同主串就往前移⼀位,从下⼀位开始再和模式串对⽐,每次只移动⼀位,这样会很慢,所以就有三位⼤神⼀起搞了个算法,也就是我们现在所称的KMP算法~~代码以及理解源码这⾥给出~~int Index_KMP(SString S,SString T,intt next[]){int i = 1,j = 1;//数组第⼀位下标为1while (i <= S.length && j <= T.length){if (j == 0 || S.ch[i] == T.ch[j]){//数组第⼀位下标为1,0的意思为数组第⼀位的前⾯,此时++1,则指向数组的第⼀位元素++i;++j; //继续⽐较后继字符}elsej = next[j]; //模式串向右移动到第⼏个下标,序号(第⼀位从1开始)}if (j > T.length)return i - T.length; //匹配成功elsereturn 0;}接下来就可以跟我来理解这个代码~~还不会做动图,这⾥就⼿画了~~以上是⼀般情况,那么如何理解j=next[1]=0的时候呢?是的,这就是代码的思路,那么这时我们就知道,核⼼就是要求next数组各个的值,对吧,⼀般也就是考我们next数组的值为多少~~next数组的求解这⾥先需要给出概念,串的前缀以及串的后缀~~串的前缀:包含第⼀个字符,且不包含最后⼀个字符的⼦串串的后缀:包含最后⼀个字符,且不包含第⼀个字符的⼦串当第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则:next[j]=S的最长相等前后缀长度+1与此同时,next[1]=0如,模式串"ababaa"序号J123456模式串a b a b a anext[j]0当第六个字符串匹配失败,那么我们需要在前5个字符组成的串S"ababa"中找最长相等的前后缀长度为多少再+1~~如串S的前缀可以为:"a","ab","aba","abab",前缀只不包括最后⼀位都可串S的后缀可以为:"a","ba","aba","baba",后缀只不包括第⼀位都可所以这⾥最⼤匹配串就是"aba"长度为3,那么我们+1,取4序号J123456模式串a b a b a anext[j]04再⽐如,当第⼆个字符串匹配失败,由前1个字符组成的串S"a"中,我们知道前缀应当没有,后缀应当没有,所以最⼤匹配串应该为0,那么+1就是取1~~其实这⾥我们就能知道⼀个规律了,next[1]⼀定为0(源码所造成),next[2]⼀定为1(必定没有最⼤匹配串造成)~~序号J123456模式串a b a b a anext[j]014再再⽐如,第三个字符串匹配失败,由前两个字符组成的串S"ab"中找最长相等的前后缀长度,之后再+1~~前缀:"a"后缀:"b"所以所以这⾥最⼤匹配串也是没有的长度为0,那么我们+1,取1序号J123456模式串a b a b a anext[j]0114接下来你可以⾃⼰练练4和5的情况~~next[j]011234是不是很简单呢?⾄此,next数组的求法以及kmp代码的理解就ok了~~那么接下来,在了解以上之后,我们想⼀想KMP算法存在的问题~~KMP算法存在的问题如下主串:"abcababaa"模式串:"ababaa"例如这个问题我们很容易能求出next数组序号J123456模式串a b a b a anext[j]011234此时我们是第三个字符串匹配失败,所以我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,可是我们刚开始的时候就已经知道模式串的第三个字符"a"和"c"不匹配,那么这⾥不就多了⼀步⽆意义的匹配了么?所以我们就会有kmp算法的⼀个优化了~~KMP算法的优化我们知道,模式串第三个字符"a"不和主串第三个字符"c"不匹配,next数组需要我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,之后就是模式串第⼀个字符"a"不和"c"匹配,就是需要变为next[1]=0,那么我们要省去步骤,不就可以直接让next[3]=0么?序号J12345模式串a b a b anext[j]01123nextval[j]00那么怎么省去多余的步骤呢?这就是nextval数组的求法~~nextval的求法以及代码理解先贴出代码for (int j = 2;j <= T.length;j++){if (T.ch[next[j]] == T.ch[j])nextval[j] = nextval[next[j]];elsenextval[j] = next[j];}如序号J123456模式串a b a b a anext[j]011234nextval[j]0⾸先,第⼀次for循环,j=2,当前序号b的next[2]为1,即第⼀个序号所指向的字符a,a!=当前序号b,所以nextval[2]保持不变等于next[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]01第⼆次for循环,j=3,当前序号a的next[3]为1,即第⼀个序号所指向的字符a,a=当前序号a,所以nextval[3]等于nextval[1]=0序号J123456模式串a b a b a anext[j]011234nextval[j]010第三次for循环,j=4,当前序号b的next[4]为2,即第⼆个序号所指向的字符b,b=当前序号b,所以nextval[4]等于nextval[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]0101就是这样,你可以练练5和6,这⾥直接给出~~序号J123456模式串a b a b a anext[j]011234nextval[j]010104⾄此nextval数组的求法你也应该会了,那么考研要是考了,那么是不是就等于送分给你呢?⼩练习那么你试着来求⼀下这个模式串的next和nextval数组吧~~next[j]nextval[j]⼩练习的答案序号j12345模式串a a a a b next[j]01234 nextval[j]00004。
浅析串模式匹配算法KMP及应用

文献标识码
S m p e An lss o i l ay i f KM P g rt m n pia in o te n M a c i g i ti g Alo i h a d Ap l t f Pa tr c o th n n S rn
Wa n a g ng Xi y n
新 的 科 学 领 域 中 不 断 的突 破 , 为特 殊 信 息 的检 索 技 术 提 供 了全 新 的解 决 方
案。 第 三ຫໍສະໝຸດ 次 匹 配 := i7则 当前 扩 展 结 点就 不 再是 一 个 活 结 点 。 时, 此 应继续移 动至 下一个活结 点
处 ,并 使这 个 活 结 点 成 为 当 前 的 扩 展
固 固
lK P算法结构 M
11 解 空 间 的确 定 .
结点 。无 回溯法 即 以这种 工作方式递
归地在解 空间 中搜 索 ,直至 找到所要
求 的 解 或 解 空 间 中 已 没 有 活 结 点 时 为
止。
应 用 无 回溯 算 法 解 决 实 际 问题
时, 首先 要 确 定 问题 的解 空 间 , 问 题 即
当前的扩展结 点。在 当前 的扩展结点 处, 搜索 向纵 深方 向移至 一个新结点 。 这个 新结 点就 成为 一个 新 的活 结点 ,
并 成 为 当前 扩 展 结 点 。 如 果 在 当 前 的 扩 展 结点 处不 能再 向纵深方 向移 动 ,
固 回
索逐步扩 展到 串行通 讯技术 、生物序 列模式 自动 识别、 数据信息共 享 、 多元 化检 验等领域 。K MP在继 承了 自身特 点的 同时 , 结合现代 信息存储 技术 , 在
KMP Alo tm ru h h n lss o h i l lo tm d te bg etie t a ayi fte agrtm. — g r h t o g te a ay i fte smpe ag r h a I igs d nil a l sso h lo h i h i n l c n i T ru h c mp rn e a ayi i o lxt h o g o aig t n lsso t h f me c mpei o KMP A g r m i e smpe ag r m, c ivs te yf - loi h t w t t i l oi h h l h t i a he e t h
ds-kmp算法 -回复

ds-kmp算法-回复dskmp算法原理、应用领域和优势随着数据规模的不断增大和复杂度的加深,对数据进行分析和处理变得越来越重要。
在数据处理领域,诸如图形图像处理、机器学习和计算机视觉等任务中,搜索和匹配算法是至关重要的一环。
这就引出了dskmp算法的概念。
在本文中,我们将一步一步地探讨dskmp算法的原理、应用领域和优势。
首先,让我们来了解一下什么是dskmp算法。
dskmp是Distributed Sakoe-Chiba-k-Means Partitioning(分布式Sakoe-Chiba-k均值分区)的缩写。
它是一种用于数据搜索和匹配的算法,主要用于处理时间序列数据。
该算法能够在分布式环境下高效地对大规模的时间序列数据进行聚类和查询。
dskmp算法的核心原理是将时间序列数据划分成多个区域,并对每个区域进行聚类。
它使用了Sakoe-Chiba k均值算法来进行聚类,这个算法是对传统的k均值算法进行改进,使其能够处理时间序列数据。
与传统的k 均值算法不同,Sakoe-Chiba k均值算法通过引入时间序列的约束条件来限制数据点之间的距离。
通过这种方式,该算法能够在处理时间序列数据时具有更好的表现。
除了聚类之外,dskmp算法还具有强大的查询功能。
它使用了分布式存储和索引技术来加快查询速度。
通过将数据存储在多个节点上,并使用索引结构对数据进行组织,dskmp算法能够高效地进行查询操作。
这使得在海量时间序列数据集中进行匹配成为可能。
dskmp算法的应用领域非常广泛。
其中一个典型的应用是图形图像处理。
在图像处理中,我们经常需要对图像数据进行搜索和匹配。
通过使用dskmp算法,我们可以在图像库中高效地查找和匹配相似的图像。
这种技术在人脸识别、图像检索和图像分类等任务中具有很大的潜力。
另一个应用领域是机器学习。
机器学习需要处理大量的数据,并从中学习模式和规律。
通过使用dskmp算法,我们可以在大规模时间序列数据集中进行聚类和查询操作,从而发现隐藏在数据中的关联性和模式。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
01求子串在母串中所有出现的位置给定主串S和模式串T,求T串在S串中所有出现的位置,允许不同位置的T串有部分重叠。
例如:S='abababab',T='abab',T在S中出现的总次数就是3次(包括1、3、5三个起点位置,虽然S[1..4]与S[3..6]有部分重叠,但这是允许的)。
输入信息包括两行,第一行为S串,第二行为T串;按从小到大的顺序输出所有T串出现的位置。
样例:02求多字符串的最长公共子串(POW)给定n个字符串,求这n个字符串的最长公共子串。
例如给3个字符串:'abcb'、'bca'和'acbc',则这三个字符串的最长公共子串即为'bc'。
输入第一行为n,下面n行即为这n个字符串。
输出它们的最长公共子串。
样例:03最长回文子串问题顺序和逆序相同的字符串便是回文串(例如‘aba‘)。
求一个字符串所有的子串中最长的回文串便是最长回文子串问题。
输入内容为一个字符串,输出它的最长回文子串。
样例:04 L-Gap子串问题(gap.pas)如果一个字串形如UVU,U非空,且V恰好有L个字符,我们就称这种UVU形式的字串是一个L-Gap串。
例如,abcbabc是1-Gap 字串,xyxyxyxyxy 既可以是一个2-Gap 字串,也可以是一个6-Gap字串,但它不是一个10-Gap字串(因为U 必须非空)。
现在的问题时,给定一个字串s和一个正整数g, 请你在s串中找出所有的g-Gap子串,并输出所有的g-Gap子串总数。
规定s串仅由小写字母组成,且其长度不超过50,000。
输入:Input第一行为一个数字t(1<=t<=10),表示测试点的个数。
以后的t行,每行有一个数字g(1<=g<=10) 和一个字串s。
输出:对于每一组数据,输出该组数据中所包含的g-Gap 子串的数目。
示例:输入:输出:2 71 bbaabaaaaa 15 abxxxxxab[注]L-Gap Substrings标准算法是二分+扩展KMP 或者后缀树我用的是ZhouYuan教我的O(n^2)加常数优化的方法UvU形式, 枚举长度U的长度L , 设数组B,如果S[i] = S[i + g + L],那么B[i]为1 , 否则B[i]为0。
如果存在连续L个1,那么就是答案了。
先比较前L个,如果都是1,那么就是答案,继续比较。
如果在第i的位置出现了一个0,那么下一个有可能的答案的开始位置至少是i+1了。
这个算法大约是答案级别的。
然后想,如果答案比较大,必然是重复串比较多。
设F[i][k]表示i开始长度为k的循环串循环了多少次。
k = 1..10. 通过这个预处理有一些答案就可以直接算而不需要比较了。
经试验,只需要计算k=1的情况程序速度就已经非常快了。
05病毒(Timelimit :0.5S Name:Virus)一天TZ的电脑遭到了病毒袭击,他的硬盘空间一下子就被占满了。
于是他找到了计算机组的―暴力杀病毒‖——LQS,请他来帮忙。
LQS研究了一下,发现这个病毒复制的文件都包含一长的01串,并且每个01串都包含了一个固定的子串。
在同一个硬盘内,复制的01串是不可能相同的,所以说,该病毒并不会无限制的复制。
由于人称―暴力杀病毒‖,LQS很轻松的杀掉了该病毒。
不过TZ对该病毒产生了浓厚的兴趣,他想计算一下,如果不考虑占满硬盘空间,在同一个硬盘里面,该病毒最多可以复制多少份?他本来想请LQS来帮他解决这个问题,可是LQS说:我要暴力搞密码!看来现在只好请聪明的你来帮他解决这个难题了。
输入第一行母串长度N和子串长度M(1<=M<=N<=2000)。
第二行为一个长度为M的01串,即每个母串应包含的子串。
输出满足条件的母串个数。
由于这个值可能很大,所以只要你输出其除以10000的余数。
样例输入3 210样例输出406[注] 我们可以采用补集转化思想。
因为长度为N的二进制串个数是很容易算出的。
所以,如果求出这些串中间有多少个不包含给定的子串,也就等于求出了有多少个包含了给定的子串。
假定给定的子串为St。
令f[i,j]表示符合下列两个条件的串S的数目。
(1)S的长度为i。
(2)S[I-J+1]..S[I]=St[1]..St[J]。
且j是满足该式最大的一个。
根据该定义我们不难列出动态转移方程:(1)若S[I+1]=St[J+1],则F[I+1,J+1]=F[I+1,J+1] + F[I,J](2)若S[I+1]<>St[J+1],则F[I+1,K]=F[I+1,K]+F[I,J](其中K表示加上S[I+1]后得到的新状态。
显然不包含St的母串个数为F[N,0]+F[N,1]……+F[N,Len(St)- 1]算法的基本框架已经得出,现在我们要考虑的是怎么尽快得求出前面提到的K值,假定求K的时间复杂度为O(1),那么整个算法的时间复杂度为O(N^2),已经不能再高了,所以我们必须用O(1)的复杂度来求K。
这就让我们想到了KMP算法。
当出现S[I+1]<>St[J+1]时,实际上就是表示匹配到这里就结束了,我们必须通过Next函数来得到下次匹配的参量。
因为这是一个01串,因此不难证明K=Next[J+1]。
这样一来,求K的复杂度就成功的降为了O(1),采用滚动数组的话,空间复杂度可以降为O(N),问题解决了。
06 电话号码(phone.pas)在今天的世界,你经常会遇到许多的电话号码,而且电话号码也越来越长。
你需要记住这些号码。
有一种简单的方法是将字母分派给数字,如下图所示:1 I J2 ABC3 DEF4 GH5 KL6 MN7 PRS 8 TUV 9 XY 0 OQZ在这种方法下,每个单词或每组单词对应指定的唯一一个号码,这样你就可以用记忆单词来代替记忆电话号码。
明显地,如果能够找到某单词和此人自身的一些简单的关系,那么这种方法就显示了它的魔力。
这样,你就能知道你的一个棋友的电话号码941837296能被读作WHITEPAWN,你的最喜爱的老师的电话号码2855304被读作BULLDOG。
写一个程序,找到与一给定号码和所给出单词列表相对应的单词的最短序列(即可能的最少数目的单词数)。
这种对应见上图。
输入:输入文件PHONE.IN的第一行包括一个你将要找其副本的电话号码,号码最多只能由100个数字组成。
第二行包括字典中单词的总个数(最大为50000),接下来的每一行包括一个单词,每个单词由最多不超过50个的英文小写字母构成,输入文件总大小不超过300千字节。
输出:输出文件PHONE.OUT中有唯一的一行,它包括用你的程序找出的最短的单词序列。
这些单词之间用空格隔开。
如果对输入的数据无结果,则显示―NOSOLUTION‖;如果有多个结果有同样的最短的单词序列,你可以任选择其中的一种。
例子:对输入文件PHONE.IN有唯一的结果。
PHONE.IN中包括73251890875ITYOURREALITYREALOUR在输出文件PHONE.OUT中显示:REALITY OUR(另一种可能为‗REAL IT YOUR‘对应同一号码,但它较长)如果号码为‗4294967296‘,则唯一正确的结果是:NO SULUTION。
因为当我们要找与4对应的字母时,没有任何给出的单词包含字母G和H。
[注]动态规划。
状态f[i]表示前i位最少用多少单词,由于一个单词最多50个字符,则对于f[i]可转移状态不会超过50个,方程是:f[i]=min{f[i-v]+1}(i-v+1..i可组成一个单词)。
对于每个单词利用kmp算法求出以此单词转移的所有状态对,又由于单词300kb,可以采用读两遍的方法避免存储。
[2]该题可以用动态规划解决。
最容易想到的动态转移方程是:f[I] = min{f[I – length(word[j])] } + 1f[0] = 0其中f[I]表示转换成数字串的前I位所需的最少单词数。
word数组存储一切可以通过转换规则变为数字串第k位至第I位的单词(k<=I)。
现在我们要考虑的问题是如何求出word数组,最简便的方法是把所有的单词都保存下来,当每次求F[I]的值以前都用一个双重循环求出word数组。
由于n最大可以达到50000,显然用静态空间是无法保存得下来的。
我们只好用动态空间来存储(可以采用链表或二维数组),因为本题的数据最大也只有300K,用上面两种方法能够解决它,但我们可以采用一种更加节省空间的方法来做这道题。
我们可以想到,一个单词能转换成的子串一定很少,甚至有的单词根本就不能转换成一个子串,但我们在求解的过程中仍要把这些单词保存下来,这显然是没有必要的。
其实我们可以边读边处理。
设can[I,J]表示可以转换成原串第I-J+1至第I位的单词,从前面的方程我们不难想到当有多个这样的单词时,只选一个加入word数组是不会对解造成影响的,因此can[I,J]最多只要对应一个单词就足够了。
这么一来每读入一个单词就可以对can数组做一次更新,更新完后这个单词就可以不用再保存了。
这就及时地去除了一些多余的单词,使空间得到了充分利用,而此时的can数组也就成了原来的word数组。
经过这一优化后,处理word数组所需的空间由50000*50降到了50*50*100,空间上得到了很好的优化。
07机器人的名字(COMPRESS.EXE)问题描述:公元2020年,数量极为巨大的智能化机器人充斥了整个星球,每个机器人都有一个仅由英文字母和空格组成的名字,并且不能出现两个机器人重名的情况(正如你所知道的那样,在这个全球联网的时代,重名就意味着将充电账单记在另一个机器人名下等严重的问题),所以,机器人的名字已经出现了不断增长的趋势。
本来,使用数字命名法是解决问题的很好方法,但是,新通过的ARR(Act of Robot Rights),已经禁止了数字命名等歧视机器人的行为,而且赋予了机器人在不导致重名的前提下,选择个性化名字的权利,这无疑进一步助长了盲目加长名字的倾向。
很快,这一趋势就带来了许多麻烦,如存储器缺货等。
所以,CRR(Commission on Robot Rights)需要你编写一个能够将机器人的名字尽可能压缩的程序来解决这个问题,并输出名字的最短压缩长度,以便CRR能够为每个机器人分配一个大小适当的MON(Memory of Name)。
考虑到各种机器人的知识水平(有相当数量的机器人不能理解哈夫曼编码),以及他们起名字的习惯(很多机器人喜欢使用有大量重复段的名字),所以,你被要求使用一种比较易于理解的压缩方法:对名字中的重复子串进行压缩,即用[St]k表示k个相同的子串St(其中,St称为重复子串,k是一个单字节整数,只占一个字符位置),如果这k个子串并没有连在一起,则可以在[St]k的后面加上{S1} t1{S2} t2…{S r} t r(其中,1<t i<k,t i<t i+1,i=1,…,r),表示在第t i个St的后面放置S i,S i称为插入子串。