本题选B。
解答:
方法一:计算 next 数组
第一步:计算出模式串的next数组。默认next数组是优化后的next数组。
本人自编口诀优化前的next数组:第一格负一,第二格零,前缀等于后缀取最长。
当然实际代码中很多人习惯用优化前的next数组求解,优化后的next数组中每个值为优化前的next数组中每个值加一。
本人自编口诀优化后的next数组:第一格零,第二格一,前缀等于后缀取最长再加一。
移动位数 = 已匹配字符数 - 失配位置对应的匹配值(优化前next数组) = 5 - 2 = 3。模式串向后移动3格,重新进行匹配,这次匹配成功。
移动位数 = 失配位置 - 失配位置对应的匹配值(优化后next数组) = 6 - 3 = 3。模式串向后移动3格,重新进行匹配,这次匹配成功。
或 j 指针跳转指向模式串第 next[j] 个字符重新与主串第 i 个字符进行比较,next[6] = 3 , j 指针跳转到模式串第3个字符的位置。
第二步:遍历主串对模式串进行匹配。
第一次匹配在主串第六个位置出现失配,找到之前匹配的子串为abaab,最长相同前缀与后缀为ab,将前缀的ab移动到后缀ab的位置。
或者查表next数组失配字符c,其next值为3,c位于模式串中第6位,移动位数 = 失配位置 - 失配位置对应的匹配值 (优化后next数组)= 6 - 3 = 3。模式串向后移动3格,重新进行匹配,这次匹配成功。
匹配9次,失配1次,总比较次数:9+1=10。
本题选B。
方法二:模拟
以下以 T = bacbababaabcbab 和 P = ababaca 为例。P 中绿色(含浅绿色和深绿色)表示对应字符匹配,红色表示对应字符失配,灰色表示未比较,浅绿色表示已匹配部分的最长的相等的前缀,深绿色表示已匹配部分的最长的相等的后缀。T 中黄色表示对应字符已经比较过,灰色表示未比较。
若已匹配部分为空,则 P 继续偏移一个位置,即偏移 s 增加 1。如图中第 1 趟、第 3 趟和第 4 趟匹配。
若已匹配部分不为空,已匹配长度为 x = i - 1,找出已匹配部分的最长的相等的前缀和后缀,(寻找已匹配部分的最长的相等的前缀和后缀时,从长度为 x - 1 的前缀和后缀开始判断更好。)该长度为 y,则下一次匹配从后缀开始位置开始,即偏移 s 增加 x - y。如图中第 2 趟和第 5 趟匹配。这步跳转用到了等式的传递性,因为 且 ,所以 。KMP 算法强大的地方就在这里,相比朴素字符串匹配算法,偏移 s 不仅实现了跳跃式增长,而且下一趟匹配中当前这趟的前缀部分的无需重新比较。
接下来进入下一轮匹配,从 P 中未比较的灰色部分开始继续比较,重复上述过程直到找到一个匹配或者比较超出 T 的范围为止。
该模拟方法无需计算 next 数组,next 数组本质就是基于这个原理进行计算的。此外,由于 next 数组有多种计算方式,不同计算方式结果不同,并不方便真题进行考察。
假设已经比较了 k 趟。
这里有个注意点,第 i 趟比较后匹配次数不是第 i 趟所有匹配的字符数,例如第 2 趟匹配中,前缀 ab 是无需重新比较的,所以第 2 趟比较后匹配次数 = 4,而不是 6,这一点一定要细心。
还有一种更快捷的计算方法:
后一种计算方式更为简便。
本题选B。
方法三:贪心
贪心找到最多匹配的情况,同样画出上图。虽然这个方法不严谨,好在本题足够简单,只有开始头指针对齐的一次和完全匹配的一次,总共出现一次失配。
匹配9次,失配1次,总比较次数:9+1=10。
本题选B。
登录后提交答案