/*
有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?
*/
/**
* @brief 暴力匹配
* @param[in] s 主串
* @param[in] p 模式串
* @note 如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有:
如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;
如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。
* 时间复杂度为:O(n*m),n、m分别为主串和模式串的长度
*/
int ViolentMatch(std::string s, std::string p)
{
int i = 0;
int j = 0;
//i是s的索引,j是p的索引
while (i < s.size() && j < p.size())
{
if (s[i] == p[j]) //如果当前字符匹配成功(即S[i] == P[j]),则i++,j++
{
i++;
j++;
}
else //如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0
{
i = i - j + 1;
j = 0;
}
}
return ((j == p.size()) ? (i -j) : -1); //匹配成功,返回模式串p在文本串s中的位置,否则返回-1
}
/**
* @brief KPM算法-获取模式串的预处理数组
* @param[in] p 模式串
* @param[out] next 预处理数组
* @note
* 时间复杂度为:O(m),m分别为模式串的长度
*/
std::vector<int> GetNext(std::string p)
{
std::vector<int> next(p.size(), 0);
next[0] = -1;
int k = -1;
int j = 0;
int len = p.size();
while (j < (len - 1))
{
//p[k]表示前缀,p[j]表示后缀,在 p[k] == p[j]的
if (k == -1 || p[k] == p[j])
{
next[++j] = ++k;
}
else
{
k = next[k]; // 递归前缀索引k
}
}
return next;
}
/**
* @brief KMP算法
* @param[in] s 主串
* @param[in] p 模式串
* @note
* 时间复杂度为:O(n+m),n、m分别为主串和模式串的长度
*/
int KMP(std::string s, std::string p)
{
std::vector<int>& next = GetNext(p); // 预处理next数组,时间复杂度为O(m)
int i = 0;
int j = 0;
int s_len = s.size();
int p_len = p.size();
//i是s的索引,j是p的索引
while (i < s_len && j < p_len)
{
// 或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
if (j == -1 || s[i] == p[j])
{
i++;
j++;
}
else //如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0
{
// i不需要回溯了,如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
// i = i - j + 1;
j = next[j]; // 只有 j = next[0]; 能使j为-1
}
}
return ((j == p_len) ? (i - j) : -1); //匹配成功,返回模式串p在文本串s中的位置,否则返回-1
}