字符串模式匹配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 }

如果代码有什么问题和建议欢迎指出。

posted on 2015-02-11 12:31  S.ilence  阅读(499)  评论(0编辑  收藏  举报

导航