1.字符串

字符串∶简称为,是由零个或多个字符组成的有限序列。一般记为

  • 字符串的长度︰字符串中字符的数目n称为字符串的长度。

  • 空串:零个字符构成的串也称为「空字符串」,它的长度为0,可以表示为" "。

  • 子串∶字符串中任意个连续的字符组成的子序列称为该字符串的「子串」。并且有两种特殊子串,起始于位置为0、长度为k的子串称为「前缀」。而终止于位置n -1、长度为k的子串称为「后缀」。

  • 主串:包含子串的字符串相应的称为「主串」。

举个例子:

str="Hello world"

在示例代码中,str是一个字符串的变量名称,Hello World则是该字符串的值,字符串的长度为11。该字符串的表示如下图所示∶

2.字符串的比较

2.1字符串的比较操作

字符串之间的大小取决于它们按顺序排列字符的前后顺序。比如字符串 str1 = "abc" 和 str2 = "acc",

它们的第一个字母都是 a,而第二个字母,由于字母 b 比字母 c 要靠前,所以 b < c,于是我们可以

说 "abc" < "acd" ,也可以说 str1 < str2。

字符串之间的比较是通过组成字符串的字符之间的「字符编码」来决定的。而字符编码指的是字符在对

应字符集中的序号。

对于两个不相等的字符串,我们可以以下面的规则定义两个字符串的大小:

  • 从两个字符串的第 0 个位置开始,依次比较对应位置上的字符编码大小。

  • 如果 str1[i] 对应的字符编码等于 str2[i] 对应的字符编码,则比较下一位字符。

  • 如果 str1[i] 对应的字符编码小于 str2[i] 对应的字符编码,则说明 str1 < str2。比如:"abc" <

"acc"。

  • 如果 str1[i] 对应的字符编码大于 str2[i] 对应的字符编码,则说明 str1 > str2。比如:"bcd" >

"bad"。

  • 如果比较到某一个字符串末尾,另一个字符串仍有剩余:

  • 如果字符串 str1 的长度小于字符串 str2,即 len(str1) < len(str2)。则 str1 < str2。比如:"abc" < "abcde"。

  • 如果字符串 str1 的长度大于字符串 str2,即 len(str1) > len(str2)。则 str1 > str2。比如:"abcde" > "abc"。

  • 如果两个字符串每一个位置上的字符对应的字符编码都相等,且长度相同,则说明 str1 == str2,比如:"abcd" == "abcd"。

按照上面的规则,我们可以定义一个 strcmp 方法,并且规定:

  • 当 str1 < str2 时,strcmp 方法返回 -1。

  • 当 str1 == str2 时,strcmp 方法返回 0。

  • 当 str1 > str2 时,strcmp 方法返回 1。

2.2字符串比较代码

def strcmp (str1, str2):
    index1, index2 = 0,0
    while index1< len(str1 ) and index2< len(str2):
        if ord(str1 [index1] )== ord(str2 [ index2 ]):
            index1 += 1
            index2 += 1
    elif ord(str1[ index1])< ord(str2 [index2]):
        return -1
    else:
        return 1

    if len (str1)< len(str2) :
        return-1
    elif len(str1)> len (str2):
        return 1
    else:
        return 0

2.3字符串的字符编码

以计算机中常用字符使用的 ASCII 编码为例。最早的时候,人们制定了一个包含 127 个字符的编码表

ASCII 到计算机系统中。ASCII 编码表中的字符包含了大小写的英文字母、数字和一些符号。每个字符

对应一个编码,比如大写字母 A 的编码是 65,小写字母 a 的编码是 97。后来又针对特殊字符,将

ASCII 扩展到了 256 位。

ASCII 编码可以解决以英语为主的语言,可是无法满足中文编码。为了解决中文编码,我国制定了

GB2312、GBK、GB18030 等中文编码标准,将中文编译进去。但是世界上有上百种语言和文字,各

国有各国的标准,就会不可避免的产生冲突,于是就有了 Unicode 编码。Unicode 编码最常用的就

UTF-8 编码,UTF-8 编码把一个 Unicode 字符根据不同的数字大小编码成 1 ~ 6 个字节,常用的

英文字母被编码成 1 个字节,汉字通常是 3 个字节。

2.4字符串的存储结构

字符串的存储结构跟线性表相同,分为「顺序存储结构」和「链式存储结构」。

3.字符串匹配问题

字符串匹配:又称「模式匹配」。可以简单理解为,给定字符串 T 和 p,在主串 T 中寻找子串 p。

串 T 又被称为「文本串」,子串 p 又被称为「模式串」。

在字符串问题中,最重要的问题之一就是字符串匹配问题。而按照模式串的个数,我们可以将字符串匹

配问题分为:「单模式串匹配问题」和「多模式串匹配问题」。

3.1单模式串匹配问题

单模式匹配问题︰给定一个文本串T = tt2….tn,再给定一个特定模式串p = PPp2..pn。要求从文本串T找出特定模式串p的所有出现位置。

根据在文本中搜索模式串方式的不同,可以将单模式匹配算法分为以下三种:

  • 基于前缀搜索方法∶在搜索窗口内从前向后(沿着文本的正向)逐个读入文本字符,搜索窗口中文本和模式串的最长公共前缀。著名的KMP算法和更快的 Shift-Or算法使用的就是这种方法。

  • 基于后缀搜索方法:在搜索窗口内从后向前(沿着文本的反向)逐个读入文本字符,搜索窗口中文本和模式串的最长公共后缀。使用这种搜索算法可以跳过一些文本字符,从而具有亚线性的平均时间复杂度。最著名的 BM 算法,以及 Horspool 算法Sunday 算法都使用了这种方法。

  • 基于子串搜索方法:在搜索窗口内从后向前(沿着文本的反向)逐个读入文本字符,搜索满足「既是窗口中文本的后缀,也是模式串的子串」的最长字符串。与后缀搜索方法一样,使用这种搜索方法也具有亚线性的平均时间复杂度。这种方法的主要缺点在于需要识别模式串的所有子串,这是一个非常复杂的问题。Rabin-Karp 算法BDM 算法BNDM 算法 BOM 算法使用的就是这种思想。其中,Rabin-Karp 算法使用了基于散列的子串搜索算法。

3.2多模式串匹配问题

多模式匹配问题∶给定一个文本串,再给定一组模式串,其中每个模式串是定义在有限字母表上的字符串。要求从文本串T中找到模式串集合Р中所有模式串的所有出现位置。

模式串集合Р中的一些字符串可能是集合中其他字符串的子串、前缀、后缀,或者完全相等。解决多模式串匹配问题最简单的方法是利用「单模式串匹配算法」搜索r遍。这将导致预处理阶段的最坏时间复杂度为,搜索阶段的最坏时间复杂度为

如果使用「单模式串匹配算法」解决多模式匹配问题,那么根据在文本中搜索模式串方式的不同,我们也可以将多模式串匹配算法分为以下三种∶

  • 基于前缀搜索方法∶搜索从前向后(沿着文本的正向)进行,逐个读入文本字符,使用在P上构建的自动机进行识别。对于每个文本位置,计算既是已读入文本的后缀,同时也是P中某个模式串的前缀的最长字符串。著名的AC自动机算法Multiple Shift-And算法使用的这种方法。

  • 基于后缀搜索方法∶搜索从后向前(沿着文本的反向)进行,搜索模式串的后缀。根据后缀的下一次出现位置来移动当前文本位置。这种方法可以避免读入所有的文本字符。Set Horspool算法wu-Manber算法使用了这种方法。

  • 基于子串搜索方法︰搜索从后向前(沿着文本的反向)进行,在模式串的长度为min(len(p'))的前缀中搜索子串,以此决定当前文本位置的移动。这种方法也可以避免读入所有的文本字符。Multiple BNDM算法SBDM算法SBOM算法都使用了这种方法。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐