暴力
KMP
RabinKarp
假设主串为s,模式串为pattern
RabinKarp算法的思想就是,将模式串通过哈希函数映射为一个哈希值,然后计算在主串中与模式串相同长度的子串(我在这里将其定义为一个窗口)的哈希值,如果窗口哈希值与模式串的哈希值相等,那么再逐个比较字符串中的每个字符是否相同,如果相同,返回窗口第一个元素的下标,反之窗口右移一位,继续比较,直到剩余元素少于模式串的长度为止。
使用哈希映射就必然会存在哈希值冲突的问题,因此采用除留余数法来降低出现冲突的概率
除留余数法的性质:如果在每次操作后都将结果除以Q并取余,等价于在完成了所有算术运算后再将最后的结果除以Q并取余。

// 检查字符串是否匹配bool check(string s, string pattern, int i) {for (int j = 0; j < pattern.size() && i + j < s.size(); j++) {if (pattern[j] != s[i + j])return false;}return true;}// 计算从索引0开始长度为m的子串的哈希值long long computeHash(const string &s, const int &len, const long long &q, const int &R) {long long hashValue = 0;for (int i = 0; i < len; i++) {hashValue = (hashValue * R + s[i]) % q;}return hashValue;}// RabinKarp算法int RabinKarp(string s, string pattern) {int n = s.size();int m = pattern.size();if (m > n)return -1; // 不匹配int R = 256;long long q = 1000000006; // q 是一个很大的素数long long patHash = computeHash(pattern, m, q, R); // 计算模式串的哈希值long long sHash = computeHash(s, m, q, R);if (patHash == sHash && check(s, pattern, 0))return 0; // 匹配成功// 如果第一次没配成功的话执行下面的操作long long rm = 1; // 用于减去窗口第一个字符for (int i = 0; i <= m - 1; i++) {rm = (rm * R) % q;}for (int i = m; i < n; i++) {sHash = ((sHash + q - rm * s[i - m]) % q) % q; // 连续取两次是为了减少冲突的概率,可以不减sHash = (sHash * R + s[i]) % q;if (sHash = patHash && check(s, pattern, i - m + 1))return i - m + 1;}return -1;}
