算法實現--KMP算法-匹配字符串

/*
有一個文本串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
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章