KMP 算法
KMP算法是一种用于快速找出匹配的子字符串位置的算法。通过记录要匹配的字符串各位置前面子字符串最长相同前后缀的信息,达到加速匹配过程的效果。
前缀字符串是指从前向当前字符串位置数的字符串;后缀字符串是指从后向当前字符串数的字符串。这里是不包含自身位置的。例如字符串"aaabaa",其相同前缀缀长度是
a |
a |
a |
b |
a |
a |
b |
-1 |
0 |
1 |
2 |
0 |
1 |
2 |
这里我们规定最前的字符对应的是-1,第二个字符因为前面字符串只有一个字符,所有记作0。
第三个字符是a
,它前面的字符串是"aa",将这个字符串从前数和从后数,得到的最长字符串长度是1(因为不包含自身),所以记作1.
第四个字符是b
,它前面的字符串是"aaa",那么从前数最长的前缀字符串是"aa",从后数,最长的后缀字符串是"aa",且两者匹配,那就记作2。
同理,第5个字符a
,它前面的字符串是"aaab",因为从前数第一个字符是"a",从后数第一个"字符是"b",直接不匹配,那它就是0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
vector<int> getNextArray(string m) { if(m.size() == 1) { return vector<int> {-1}; } else if(m.size() == 2) { return vector<int> {-1, 0}; } vector<int> next_arr{-1, 0};
int index = 2; int cn = 0; while (index < m.size()) { if (m[index - 1] == m[cn]) { next_arr.push_back(cn + 1); cn = next_arr.back(); ++index; } else if (cn > 0) { cn = next_arr[cn]; } else { next_arr.push_back(0); ++index; } } return next_arr; }
int KMP (string s, string m) { if(s.size() == 0 || m.size() == 0 || s.size() < m.size()){ return -1; } vector<int> arr_s; vector<int> arr_m; vector<int> nextArr = getNextArray(m); int index_s = 0; int index_m = 0; while (index_s < s.size() && index_m < s.size()) { if(s[index_s] == m[index_m]) { index_s ++; index_m ++; } else if (index_m == 0) { index_s ++; } else { index_m = nextArr[index_m]; } } return index_m == m.size()? index_s - index_m: -1; }
|