【算法】字符串匹配

1.經典的KMP算法

  • 時間複雜度O(n+m):其中n爲文本串s的長度,m爲模式串p的長度。因爲首先要遍歷模式串求解部分匹配數組next,然後遍歷文本串尋找匹配起始字符的下標。

  • 空間複雜度爲O(m):其中m爲模式串的長度,用來存放next數組。

// kmp參考代碼
//      p: a  b c d a b d a
// next: -1 0 0 0 0 1 2 0
// 可以直觀理解爲先求出最長前綴後綴公共長度,然後右移一位得到next的結果。
void get_next(std::string p, int *next)
{
	int plen = p.size();

	int i = 0;
	int j = -1;
	next[0] = -1;
	while (i<plen) {
		if (j==-1 || p[i]==p[j]) {
			i++;
			j++;
			next[i] = j;
		} else {
			// 失配時移動的位置
			j = next[j];
		}
	}
}

//      s: aaabcdabaaabcdabdamns
//      p: abcdabda
// next: -1 0 0 0 0 1 2 0
int kmp(std::string s, std::string p)
{
	if (s.empty()) return -1;
	if (p.empty()) return 0;

	int slen = s.size();
	int plen = p.size();

	std::vector<int> next(plen, 0);
	get_next(p, next);
	int i = 0;
	int j = 0;
	while (i<slen)
	{
		if (j==-1 || s[i]==s[j]) {
			i++;
			j++;
		} else {
			j = next[j];
		}
		if (j==plen) break;
	}

	if (j==plen)
		return i-j;

	return -1;
}

2.效率更高的Sunday算法

  • 時間複雜度O(n):其中n爲文本串s的長度。因爲只需要遍歷文本串一遍,跳過的間隔相比kmp更大。

  • 空間複雜度O(1):只用到有限的幾個指示變量。

// sunday
// 尋找next所指向的字符在模式串的最右側出現的位置,然後更新next的值
void helper(std::string p, int plen, char ch, int *next)
{
	int pos = plen-1;
	for (int i=plen-1; i>=0; i--)
	{
		if (p[i]==ch) {
			pos = i;
			break;
		}
	}
	// 模式串中不包含ch字符,則next向後再移動一位
	if (pos==plen-1 && ch!=p[pos])
	{
		(*next)++;
	} else {
		// 如果找到了字符所在位置,則更新next的值
		*next -= pos;
	}
}

// aaabcdabaaabcdabdamns
// abcdabda
int sunday(std::string s, std::string p)
{
	if (s.empty()) return -1;
	if (p.empty()) return 0;

	int slen = s.size();
	int plen = p.size();

	int i = 0;
	int j = 0;
	int next = 0;
	while (i<slen)
	{
		j = 0;
		next = i+plen;
		if (s[i]!=s[j]) {
			if (next<slen)
				helper(p, plen, s[next], &next);
			i = next;
		} else {
			// 字符匹配時繼續查看下一位
			while (s[i]==s[j]) {
				if (s[i]!=s[j]) {
					if (next<slen)
						helper(p, plen, s[next], &next);
					i = next;
					break;
				}
				i++;
				j++;
			}
		}

		if (j==plen) break;
	}
	if (j==plen)
		return i-j;

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