字符串科技

你说的对,但字符串或串(String)是由数字、字母、下划线组成的一串字符。一般记为 s="a1a2···an"(n>=0)。它是编程语言中表示文本的数据类型。在程序设计中,字符串(string)为符号或数值的一个连续序列,如符号串(一串字符)或二进制数字串(一串二进制数字)。

字符串匹配

你说的对,但字符串匹配是计算机科学中最古老、研究最广泛的问题之一。一个字符串是一个定义在有限字母表∑上的字符序列。例如,ATCTAGAGA是字母表∑ = {A,C,G,T}上的一个字符串。字符串匹配问题就是在一个大的字符串T中搜索某个字符串P的所有出现位置。其中,T称为文本,P称为模式,T和P都定义在同一个字母表∑上。

一些定义:

字符串匹配:又称模式匹配(pattern matching)。该问题可以概括为「给定字符串 $ S $ 和 $ T $,在主串 $ S $ 中寻找子串 $ T $」。字符 $ T $ 称为 模式串 (pattern)。

暴力做法:从主串 $ S $ 的每个位置开始与模式串 $ T $ 向后匹配,若匹配不成功,则从主串下一个位置与模式串重新匹配。

时间复杂度:$ O(nm) $

实际上暴力算法在随机数据下表现良好——匹配成功的字符数量越多,匹配的概率越低。

但卡到 $ O(nm) $ 也很容易(

KMP 算法

主要思想:充分利用匹配失败的信息,跳过某些已经判断为匹配失败的位置。

如果字符串 $ s $ 的长度为 $ d $ 的前缀 $(1≤d<|s|)$ 和长度为 $ d $ 的后缀相等,称这个前缀是 $ s $ 的一个 border ,将前缀 $ s[1…i] $ 的最长 border 长度记作 $ next(i) $。

border 的性质:$ s[1…i] $ 的所有 border 长度分别为 $ next(i),next(next(i)),next(next(next(i)))... $。

如果当前已经成功匹配了 $ i $ 个字符,且第 $ i+1 $ 个字符不匹配,那么根据 $ next(i) $ 的定义,主串 $ S $ 中从后往前数 $ next(i) $ 位也一定都与模式串 $ T $ 中 $ 1 \sim next(i) $ 位匹配。

于是将 $ T $ 上匹配指针从 $ i $ 转到 $ next(i) $,再与 $ S $ 的字符匹配。

有点抽象,举个栗子:

S ABABABC
T ABABC

算出 $ next(i) $:

next 0 0 1 2 0

第一次匹配失败:

S ABAB.ABC
T ABAB.C
next 0 0 1 2 0

将 $ T $ 上匹配指针从 $ 4 $ 转到 $ next(4) $,继续匹配:

S ABABABC
T   ABABC
next 0 0 1 2 0

匹配成功。

这样做是 $ O(n) $ 的,因为 $ j $ 只能在匹配成功时增加 $ 1 $,最多增加 $ n $ 次,从而最多减少 $ n $ 次,也就是嵌套 $ next(i) $ 最多 $ n $ 次。

于是问题就在于如何快速求出 $ next(i) $。

暴力求显然不现实,考虑线性递推。

已知 $ next(1) \sim next(i) $,考虑如何计算出 $ next(i+1) $:

令 $ j = next(i) + 1 $

如果 $ s[j] $ 与 $ s[i+1] $ 不相等,就让 $ next(j) \to j $,直至 $ s[j] $ 与 $ s[i+1] $ 相等,此时 $ next(i+1) = next(j) + 1 $。

发现计算 $ next(i) $ 的过程实际上就是 $ S $ 与本身匹配。

posted @ 2023-08-30 15:07  象征阳光  阅读(14)  评论(0)    收藏  举报  来源