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

字符与文字

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

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

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

搜索和遍历

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

字符串匹配算法(正文)

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

暴力搜索

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

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










def brute_force(text,find): #暴力搜索

	
	start = 0 # text 比较游标
	sub = 0 # find 比较游标
	restart = 0
	while start!=len(text):
		if text[start]==find[sub]:
			start+=1
			sub+=1
		else:
			restart+=1
			start=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 += 1
			start+=1
			sub+=1
		else:
			
			if matched_char == 0:
				restart +=1
			else:
				restart+= (matched_char - match[sub-1])

			matched_char = 0
			start=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_list
	return prefix_list
def 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_list
	return suffix_list


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




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值