字符串模式匹配sunday算法
今天在做LeetCode的时候,碰到一个写字符串匹配的题目:
https://oj.leetcode.com/problems/implement-strstr/
我一看就懵了,字符串模式匹配我记得当时在上数据结构的时候,书上只写了BF和KMP算法,老师说考试“只可能会考BF”,KMP不要求掌握。
然后出于一颗探求的心,我还是看了一下KMP,这算法好难理解,于是就没记下来。
一看这题就跪了。
上网查了一些算法,好像都对sunday算法很推崇的样子,于是找了好几个看了看,算法思想挺简单的,数学证明我也懒得去了解,毕竟我也不是学数学的料。
算法的基本思想是,模式串和主串从后往前比较,遇到无法匹配的字符的时候,看主串参加匹配的最后一个字符的下一个字符,然后分两种情况:
1、如果该字符没有出现在模式串中,就把模式串向右移动模式串的长度+1个位置。
比如:主串: ababcdababa
模式串:ababa
到c的位置无法匹配,看c后面的d没有出现在模式串中,则向右移动5+1个位置,结果为:
主串: ababcdababa
模式串: ababa
也就是说移动到d后面的一个字符。
2、如果该字符出现在模式串中,则向右移动“该字符在模式串中出现的最右边那次”到字符串末尾的长度+1。
比如:主串: ababcababa
模式串:ababa
到c的位置无法匹配,看c后面的a出现在模式串中,而模式串中有3个a,我们看最右边那个a,则向右移动0+1个位置,结果为:
主串: ababcababa
模式串: ababa
具体实现C++的代码如下,匹配成功返回成功的第一个字符的下标,不成功则返回-1:
1 int strStr(char *haystack, char *needle) 2 { 3 int len_h = strlen(haystack);//主串的长度 4 int len_n = strlen(needle);//模式串的长度 5 int next[26] = { 0 };//当匹配不成功的时候,模式串向右移动的距离,每个字母对应一个距离 6 for (int i = 0; i < 26; i++) 7 { 8 next[i] = len_n + 1;//默认为模式串的长度+1 9 } 10 for (int i = 0; i < len_n; i++) 11 { 12 next[needle[i] - 'a'] = len_n - i;//根据每个字符在模式串中的位置修改移动的距离 13 } 14 int index = 0; 15 while (index <= (len_h - len_n))//开始匹配 16 { 17 int i = index; 18 int j; 19 for (j = 0; j < len_n; i++, j++) 20 { 21 if (haystack[i] != needle[j])//如果该次匹配不成功 22 { 23 if ((index + len_n) >= len_h)//这里的判别是为了防止移动距离过度,导致数组越界 24 return -1; 25 index += next[haystack[index + len_n] - 'a'];//根据主串匹配的右边那个字符对应next的数组中的位置,模式串向右移动。 26 break; 27 } 28 } 29 if (j == len_n) 30 { 31 return index; 32 } 33 } 34 return -1; 35 }
如果代码有什么问题和建议欢迎指出。