mooyyu

S1 - KMP

c++11 string 字符串模式匹配

class KMP {
	const string s;
	int ar[maxn + 1] {};
	inline void prefunc() {
		ar[0] = -1;
		int i = 0, j = -1;
		while (i < s.length()) {
			if (j == -1 || s[i] == s[j]) ar[++i] = ++j;
			else j = ar[j];
		}
	}
	inline void ntfunc() {
		for (int i = 0; i < s.length(); i++) {
			if (ar[i] != -1 && s[i] == s[ar[i]]) ar[i] = ar[ar[i]];
		}
	}
public:
	explicit KMP(string &p): s(p) { prefunc(), ntfunc(); }
	int solve(string &tar) {
		int ret = 0, i = 0, j = 0;
		while (i < tar.length()) {
			if (j == -1 || tar[i] == s[j]) {
				++i, ++j;
				if (j == s.length()) ++ret, j = ar[j];
			} else j = ar[j];
		}
		return ret;
	}
};
Simple Explanation
  • maxnpattern的最大长度, prefix的长度是pattern.length()+1, nt的长度是pattern.length()
  • 注意构造prefix数组和求解kmp主体函数中j指针的起始值不同
  • prefix[r]表示下标[0, r)序列两端真子串的最长同构长度,prefix[0]表示的序列为空,值为-1
  • 如果用prefix数组代替nt, 当p[j]!=t[i], 则不匹配, 将[0, j)左端的同构字串移动到右端继续匹配, 是kmp的主体思想
  • nt是对prefix的优化, 当[0, j)左端的同构字串的下一个字符与p[j]相同, 则一定不匹配, 即把多次移动优化为一次移动
  • 对于题目的具体要求不同, 适当修改count_patterns函数即可