KMP字符串匹配

题:28. 找出字符串中第一个匹配项的下标 https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回  -1 

示例 1:

输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。

题解见注释

 1 class Solution {
 2 public:
 3     int strStr(string haystack, string needle) {
 4         /*
 5         Knuth-Morris-Pratt(KMP)算法,可在 O„m + n” 时间完成匹配。
 6         1.寻找needle每个索引为子串的最长相等前后缀数组:前缀是指不含尾字母的所有子串,后缀是指不含首字符的所有子串,单个字符没有前后缀
 7         如needle=bbcbbd,b:0;i=1,子串bb:1(因为前缀b后缀b相等);i=2,子串bbc:0(前缀b、bb,后缀c、bc没有相等的);i=3,bbcb:1
 8         (前缀b、bb、bbc,后缀c、cb、bcb,只有b相等);i=4,bbcbb:2(前缀b、bb、bbc、bbcb,后缀b、bb、cbb、bcbb,最长是bb,长度2)
 9         i=5,bbcbbd:0。求得各个下标的最长相等前后缀构成一Next表,用于指导匹配时回朔。
10         2.匹配,根据next=[0,1,0,1,2,0]指导回退到一个位置上继续匹配
11         如haystack=bbcbbcbbd,当匹配到bbcbbc时,仅最后一个字符j=5(c)和i=5(d)d不等,这时回退到i=0匹配计算量太大,而到前一个字符b是相等的,
12         b对应的相等前缀是2,也就是说匹配到j=5(c)时,前边有两个bb是相等的,这时只需回到i=2时继续匹配就可以,i=2来源于next[5-1]
13         */
14         //1计算next数组,求最长相等前后缀
15         int n = needle.size();
16         vector<int> next(n, 0); // 首字符的前缀肯定为0
17         int j = 0; // 指向前缀的位置,i则指向每个待计算的下标
18         for (int i = 1; i < n; ++i) {
19             while(j > 0 && needle[j] != needle[i]) { // 只要不相等,j回退到前一个字符比较,或者已为0(当前i没有相等的)
20                 j = next[j - 1]; // 这里要回到上一个字符对应的最长前缀才行,
21                 // 比如adcadde,检查到i=5(d,倒数第一个d),此时j=2(c)的位置,此时不等,j不应该回到上一个j=1(d),而是d对应的next[1]=0
22             }
23             if (needle[j] == needle[i]) {
24                 ++j;
25             }
26             next[i] = j;
27         }
28 
29         // 回溯匹配
30         for (int j = 0, i = 0; j < haystack.size(); ++j) {
31             // 原理写成了if,haystack=abbababbabbbabaaa,next=abbabbbabaa会出现回溯一次后,i=2(b)继续匹配,此时是不等的,还需继续回溯
32             while (haystack[j] != needle[i] && i > 0) { // 这里是while,不是if
33                 i = next[i - 1];
34             }
35             if (haystack[j] == needle[i]) {
36                 if (i == n - 1) return j - i;
37                 ++i;
38             }
39         }
40         return -1;
41     }
42 };

 

posted @ 2023-07-20 17:32  00lab  阅读(21)  评论(0编辑  收藏  举报