关于的字符串的总结(群,子群,KMP算法,正则表达式):
字符串:群:? 群是一种只有一个运算的,简单的线性结构,可用来建立许多其他代数系统的一种基本结构. ? 设G是一个非空集合,a,b,c为它的任意元素.如果对G所定义的一种代数运算"."满足:
满足交换律是交换群子群:? 设H是群<G,.>的非空子集,则H是G的子群当且仅当H满足以下条件:
1.字符串的实现:1.1基本实现问题和技术:? 字符串是字符的线性序列,可以采用线性表的各种实现技术实现,用顺序表或者链接表的形式表示.不论如何表示,实现的基础都是基于顺序存储或链接存储. ? 考虑字符串的表示时,有两个重要的方面必须确定:
弊端:连续存储需要很大的连续空间,极长的字符串可能会带来问题,而一个字符一块存储,需要附带链接域,增大存储开销.实际中可以采用某种中间方式,把一个字符序列分段存储在一组存储块里,并连接起这些存储块.
python的字符串:python标准类型str可以看作是抽象的字符串概念的一种实现,str是一个不变类型,对象创建后内容和长度不变,但不同的str对象长度可能不一样,因此,在Python中str对象才用了一体式顺序表形式, 如图所示:一个字符串对象的头部,除了记录字符串的长度外,还记录了一些解释器用于管理对象的信息. str的操作:
str构造操作的实现:
字符串匹配:(子串查找)假设有两个串(其中ti,pj是字符): 串匹配和朴素匹配算法:串匹配算法:? 做字符串匹配的基础是逐个比较字符. ? 如果从目标串的某个位置i开始,模式串里的每个字符都与目标串里的对应字符相同,就是找到了一个匹配.如果遇到了一个不匹配的字符,那就是不匹配.串匹配算法设计的关键有两点:
针对这两点不同的处理策略,就形成了不同的串匹配算法.从朴素匹配算法,KMP匹配算法可以看出情况. 朴素的串匹配算法:最简答的朴素匹配算法采用最直观可行的策略:
#朴素串匹配算法: #目标串t=t1t2t3....tn,模式串p=p1p2p3...pm def naive_matching(t,p): m,n=len(p),len(t) i,j=0,0 while i < m and j<n: if p[i]==t[j]: i,j = i+1,j+1 else: i,j-i+1 if i == m: #当i==m时,说明i已经比较出0到m-1的字符的匹配,说明匹配成功 return j-i return -1 #无匹配,返回特殊值 缺点:算法易实现,但是效率低,这种需要比较n-m+1,总的比较次数是m*(n-m+1),时间复杂度O(m*n) 无回溯串匹配算法:(KMP算法)KMP算法是一个高效的串匹配算法.区别看图 这里主要看pi匹配失败了,模式串怎么前移?根据模式串p本身情况决定,完全可以实际地与任何目标串匹配之前,通过对模式串本身的分析,解决好匹配失败是应该如何前移? 从上面的分析来看,对p中的每个i,都有与之对应的下标ki,与被匹配的目标串无关.有可能通过对模式串的预分析,得到每个i对应的ki.假定模式串p的长度是m,现在需要对每个i(0<=i<m)计算出对应的ki并将其保存起来,以便在匹配中使用.为此,我们考虑用一个长为m的表pnext,用表元素pnext[i]记录与i对应的ki值. 这里有一个特殊情况,在一些pi的匹配失败时,有可能发现pi匹配之前就做过的所有模式串字符与目标串的比较都没有实际利用价值.这样的话,下一步就应该从头开始,用p0匹配与tj+1比较,如果遇到这种情况时,就在pnext[i]里存入-1,显然对任何模式都有pnext[0]=-1 #KMP的基本算法是不回溯 while j<n and i<m: if i == -1: i,j+1 elif t[j] == p[i]: i,j+1 else: i = pnext[i] #显然前两个if分支可以合并,并循环简化: while j < n and i < m: if i == -1 or t[j] == p[i]: j,i = j+1,i+1 else: i = pnext[i] 解释:当t[10]与p[6]匹配失败时,KMP不是跟保利匹配那样简单的把模式串右移一个单位,而是执行如果i!=-1且当前的字符匹配失败(即t[j]!=p[i]),则令j不变,i=pnext[i],也就是i从6变到2 pnext数组各值的含义:代表当前的字符之前的字符串中,有多大长度的相同前缀后缀,比如pnext[j]=k,代表j之前的字符串中有最大长度是k的相同前缀后缀. #基于上述循环的匹配函数定义: def matching_KMP(t,p,pnext): j,i = 0,0 n,m = len(t),len(p) while j < n and i < m: if i == -1 or t[j] == p[i]: j,i+1 else:#失败,考虑pnext决定的下一字符 i = pnext[i] if i == m: #找到匹配,返回其下标 return j-1 return -1 #无匹配,返回特殊值 现在考虑这个算法的复杂度,关键是其中循环的执行次数.注意,在整个循环中j的值是递增的,但其加一的总次数不会多于len(t).而且,j递增时i的值也增加.而在if的另一个分支,语句i=pnext[i]总使i值减小.但if的条件有保证变量i的值不小于-1,i=pnext[i]的执行次数不会多于i值的递增次数.循环次数也不会多与O(n),n是目标串的长度. 那么我们怎么构造这个pnext表:
寻找模式串p中长度最长且相等的前缀后缀,如果存在 ? 2.求pnext ? pnext数组考虑的是除当前字符外的最长相同的前缀后缀,所以通过第一步求得的各个前缀后缀的公共元素的最大长度后,只要稍作变形即可,将第一步求得的值整体右移一位,然后赋值为-1,比如说aba来说,第三个字符a之前的字符串ab有长度是0的相同的前缀后缀,所以第三个字符a对应next值是0;而对于abab来说,第四个字符b之前的字符串aba中有长度是1 的相同前缀后缀a,所以第四个字符b对应的pnext是1.(pnext就是next数组) ? 3.根据next数组进行匹配 ? 匹配失败,i= pnext[i],模式串向右移的位数为:i-pnext[i],看图作解释: 模式串中, 那么什么是最长前缀后缀?如果给定的模式串是"ABCDABD",从左至右遍历整个模式串,其各个子串的前缀后缀如图所示: 也就是说,原模式串对应的各个前缀后缀的公共元素的最大长度表:(匹配表) 基于匹配表的匹配过程详解:失配右移位数: 已匹配字符数-失配字符的上一位字符所对应的最大长度值 假定目标串是"BBC ABCDAB ABCDABCDABDE"和模式串"ABCDABD",过程如下: 1.因为模式串中字符A与目标串的字符B,C,空格不匹配,这时还没有最长的前缀后缀,所以不断向右移一步,直至与第五个字符A匹配成功. 2.继续往后匹配,当模式串最后一个字符D跟文本串匹配时失配,显而易见,模式串需要向右移动。但向右移动多少位呢?因为此时已经匹配的字符数为6个(ABCDAB),然后根据《最大长度表》可得失配字符D的上一位字符B对应的长度值为2,所以根据之前的结论,可知需要向右移动6 - 2 = 4 位。 3.模式串向右移动4位后,发现C处再度失配,因为此时已经匹配了2个字符(AB),且上一位字符B对应的最大长度值为0,所以向右移动:2 - 0 =2 位。 4.A与空格失配,向右移动1 位。 5.继续比较,发现D与C 失配,故向右移动的位数为:已匹配的字符数6减去上一位字符B对应的最大长度2,即向右移动6 - 2 = 4 位。 经历第5步后,发现匹配成功,过程结束。 pnext表构造算法:def get_pnext(p): ''' 生成针对p中给位置中i的下一检查位置表,KMP ''' i,k,m = 0,-1,len(p) pnext = [-1]*m #初始数组元素都是-1 while i < m-1: if k == -1 or p[i]==p[k]: i,k = i+1,k+1 pnext[i]=k#设置pnext元素 else: k = pnext[k] #退到更短相同前缀. pnext生成算法的改进:def get_pnext(p): i,len(p) pnext = [-1]*m while i<m-1: if k == -1 or p[i] == p[k]: i,k=i+1,k+1 if p[i]==p[k]: pnext[i]=pnext[k] else: pnext[i]=k else: k=pnext[k] return pnext KMP算法的时间复杂度及其他:一次 2.字符串匹配问题:通配符与简单模式语言:? 在普通字符串的基础上增加通配符,形成一种功能更强大一点的模式描述语言,一个模式描述了一字符串集,能与该集合任何一个串匹配. 正则表达式:? 一个非常有意义和实用价值的模式语言为正则表达式. ? 正则表达式是一种描述字符串集合的语言,基本成分是字符集里的普通字符,几种特殊组合结构,以及表示组合的括号.一个正则表达式描述了字符集的一个特定的字符串集合.
一种简单的正则表达式:模式语言:
原始字符串:? 在python中书写字符串文字量的一种形式,这种文字量和普通文字量一样,就是str类型的字符串. ? 原始字符串的形式是在普通字符串文字量前加 ? 原始字符串其中的反斜线字符""不作为转义,在相应的字符串对象中原样保存, 元字符:? 正则表达式包re规定了一组特殊字符,成为元字符. 主要操作:
#re模块默认是贪婪模式;在量词后面直接加上一个问号?就是非贪婪模式。 m = 'abcde1232aac' regex = re.compile(r'ab.*c') print('>>:',regex.match(m).group()) reg = re.compile(r'ab.*?c') print('>>:',reg.match(m).group()) ######################################################### >>: abcde1232aac >>: abc
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |