吾之简单的KMP算法学习,字符串操作基本功

来源:互联网 发布:影视动画行业 知乎 编辑:程序博客网 时间:2024/04/30 22:27

字符与文字

字符如此普遍,构成我们语言的文字在电脑以看来字符为单位是十分合理的,我们人类的任何语言都对文字赋予了丰富的内涵,处理好每一个字符是一个负责任的一流工程师应该做的。即便是简单到不能再简单的Lisp也是把一切归为几个字符,可见几个字符的重要性。

字符串,一堆又一堆的字符,使之排序构成串,字符串操作无非有四:增、删、改、查  [   切分  ]。

字符串操作在我看来分为两类:基于比较的和基于坐标的,比较结果,和坐标位置是我们操作字符串的基准(规则)。

搜索和遍历

创造字符串,第一步就是看看它长个啥样子,遍历整个字符串便是首要目标。
程序就是在循环之中寻找目标,循环之多少决定程序之快慢,深度亦深亦浅,全在于工程师,有尺有度,有条不紊,故此Python书上。

字符串匹配算法(正文)

字符串匹配,一文一字要挨个来,有人喜从头起,有人喜欢尾始,因人而异,因时而异
本王所讲皆是从左开始按正序开始匹配,而且只是简单讲述KMP算法和暴力搜索

暴力搜索

人的一生总是从简单直接粗暴的开始,以暴制暴方便入门。要粗暴,那就要直接裸写代码强行匹配,完全不怂!

写完代码再来看以下代码的同学日后必成大器,日后必成大器,日后必成大器,重要的文字、文字、文字说三遍!










def brute_force(text,find): #暴力搜索start = 0 # text 比较游标sub = 0 # find 比较游标restart = 0while start!=len(text):if text[start]==find[sub]:start+=1sub+=1else:restart+=1start=restart #text 游标从次一项开始sub = 0 # find 游标从 头开始if sub==len(find):return start - sub #由于start 游标停在最后的匹配字符上,所以我们要减去搜索串find的长度return -1
如果以上代码看不懂,我教你一个简单快速的方法看懂,鼠标右下角,立马就懂!

当你分析懂了暴力搜索的原理(我的代码怎么表达的,弄懂restart 是什么意思),你就可以很快搞懂KMP算法是个什么鬼!


简而言之,比较俩字符串,<小明不知道小敏在哪里,而晓敏知道小明知道晓敏知道小敏在哪里> 以及<晓敏>
我们一眼就可以知道 第一个分句里没有,第二个分句有<晓敏>,我们看一眼便知道整个句子,所以瞬间出答案,同样的道理,如若我们能亚索(不,压缩)字符串做到快速遍历也是搜索之良方,不过我们不采取这种方法,而是采取一个小策略我们把<晓敏>拆开,这个句子<敏>出现次数较多,如果没有<敏>这个字,我们就可以直接跳过一些距离,直接从<小明不知道小敏在哪里>中的<在>继续查找,我想大概的意思你应该懂了那么一丢丢!
在伊犁,

很明显,GB后A 和O明显不匹配,再一个字符一个字符比较<ADA>,你这样做似不似傻哭,完全可以跳过其中的<ADA>跳到第二个<G>比较就可以提高效率
所以呢,我们需要机智的预先算出来<GBORGAB>中 两个G之间的距离来确定必要时跳跃几个字符!
如何计算每个字符需要的跳转位置呢!
假使<GBORGAB>是一个特别集合,使用其子集(如:G、GB、GBO等)前缀和后缀的共有元素来确定对应字符的跳转距离!共有元素组成的集合成为跳转表
代码如下:

def kmp(text,find): #经典的KMP(Knuth-Morris-Pratt)算法match = []prefix_list = []suffix_list = []#生成 "部分匹配表"for x in xrange(1,len(find)+1): # xrange(1,10) 生成1~9的序列str_src = find[0:x] #str_src原字符串prefix_list = prefix(str_src)suffix_list = suffix(str_src)intersection_list = [tmp for tmp in prefix_list if tmp in suffix_list]intersection_str = ''.join(intersection_list)match.append(len(intersection_str))print match#比较操作start = 0 # text 比较游标sub = 0 # find 比较游标restart = 0 #跳转游标matched_char = 0 #当前已匹配字符数while start!=len(text): #只要没有读取到text的最后一个字符就继续 读print 'comparing '+str(start)+' and '+str(sub)if text[start]==find[sub]:print 'found '+str(start)+' and '+str(sub)+'is equal'matched_char += 1start+=1sub+=1else:if matched_char == 0:restart +=1else:restart+= (matched_char - match[sub-1])matched_char = 0start=restart #text 游标从次一项开始sub = 0 # find 游标从 头开始if sub==len(find):return start - sub #由于start 游标停在最后的匹配字符上,所以我们要减去搜索串find的长度return -1 #为搜索到

def prefix(item_str): #获取item_str的前缀prefix_list = []item_str = item_str[:-1]for x in xrange(1,len(item_str)+1):prefix_list.insert(x,item_str[0:x])#print 'src='+item_str#print prefix_listreturn prefix_listdef suffix(item_str):#获取item_str的后缀suffix_list = []item_str  = item_str[0:]for x in xrange(1,len(item_str)+1):suffix_list.insert(x,item_str[x:])#print 'src='+item_str#print suffix_listreturn suffix_list


慢慢读,慢慢画吧,同学
这代码应该没什么明显的Bug!
大概,就是这样,以后争取坚持下来写博客!




0 0
原创粉丝点击