原文地址:Go使用Sunday算法实现PHP的strstr()
Sunday 算法是 Daniel M.Sunday 于1990年提出的字符串模式匹配,其核心思想是:在匹配过程中,模式串发现不匹配时,算法能跳过尽可能多的字符以进行下一步的匹配,从而提高匹配效率。
了解完定义后来看几个概念:
-
串:字符串的简称。
-
空串:长度为零的串。
-
主串:包含子串的串。
-
子串:串中任意个连续的字符组成的子序列。
-
模式串:子串的定位运算又称为串的模式匹配,是一种求子串第一个字符在主串中序号的运算,被匹配的主串称为目标串,子串称为模式串。
来看题目:实现PHP的strstr()函数,给定haystack和needle两字符串,在haystack中找出needle第一次出现的位置(从0开始),如不存在,则返回-1。
运行效果示例一:输入:haystack = "hello", needle = "ll" 输出: 2
运行效果示例二:输入:haystack = "aaaaa", needle = "bba" 输出: -1
需要说明的是,当needle为空时,应返回0。
先来假设目标串为:Here is a little Hao,模式串为:little。
接下来将目标串和模式串对齐:
根据Sunday算法,首先从头部比较,如不匹配,则找到主串中位于模式串后面的第一个字符,也就是s,如下:
之后查看模式串中是否包含这个s,不包含则从s下一个字符开始比较,如下:
如仍不匹配,则重复上面的过程找到模式串下一个元素t,如下:
此时t被包含于模式串且t出现在模式串倒数第3的位置,此时将模式串前移3,如下:
成功了有木有?
整体看下在上述过程:
-
对齐模式串和目标串,从前向后匹配。
-
关注主串中位于模式串后第一个元素。
-
如关注的元素未在子串中出现则跳过。
-
出现则移动模式串,移动位数=子串长度-元素最右出现的位置(从0开始)。
实现代码如下:
package main
import "fmt"
func main() {
fmt.Println(StrstrSunday("Here is a little Hao", "little"))
}
func StrstrSunday(haystack, needle string) int {
// 验证字符串合法性
if len(haystack) < len(needle) {
return -1
}
if haystack == needle || len(needle) == 0 {
return 0
}
// index:最终位置的索引,needleIndex:目标匹配索引
index, i, needleIndex := -1, 0, 0
for i < len(haystack) {
// 逐字节验证是否相等
if haystack[i] == needle[needleIndex] {
// index为-1说明是首次匹配到的字符
if index == -1 {
index = i
}
// 主串和模式串的索引+1
i++
needleIndex++
// 是否完成匹配验证
if needleIndex >= len(needle) {
break
}
continue
}
// 走到此处说明未完成匹配,将匹配目标索引置为默认
index = -1
// 计算主串需要移动的位置
i = i + len(needle) - needleIndex
// 如主串索引大于主串实际长度表示未匹配成功,直接返回
if i >= len(haystack) {
return index
}
// 计算下一字符在模式串中的位置
offset := 1
for j := len(needle) - 1; j > 0; j-- {
if haystack[i] == needle[j] {
offset = j
break
}
}
// 将主串索引左移指定长度,使当前字符和模式串最右匹配到的字符串对齐
i = i - offset
needleIndex = 0
}
return index
}
至此,本次分享就结束了,后期会慢慢补充别的算法。
以上仅为个人观点,不一定准确,能帮到各位那是最好的。
好啦,到这里本文就结束了,喜欢的话就来个三连击吧。
扫码关注公众号,获取更多优质内容。