字串查詢(2) KMP演算法查詢目標字串
阿新 • • 發佈:2022-02-23
先上程式碼:
class KMP { using DFA_t = vector< vector<int> >; public: KMP(const string &needle) : m_NeedleSize{ (int)needle.size() }, m_DFA(TOTAL_CHAR, std::move(vector<int>(m_NeedleSize, 0))) { if (m_NeedleSize > 0) { m_DFA[(unsigned char)needle[0]][0] = 1; } // generate dfa table by needle str for (int i = 1, j = 0; i < m_NeedleSize; i++) { unsigned char cur = needle[i]; for (int k = 0; k < TOTAL_CHAR; k++) { m_DFA[k][i] = m_DFA[k][j]; } m_DFA[cur][i] = i + 1; j = m_DFA[cur][j]; } // PrintDFA(m_DFA); } int SearchIn(const string &haystack) const { if (m_NeedleSize == 0) return 0; const int haystackSize { (int)haystack.size() }; for (int i = 0, j = 0; i < haystackSize; i++) { j = m_DFA[(unsigned char)haystack[i]][j]; if (j == m_NeedleSize) { return i - j + 1; } } return -1; } private: static const int TOTAL_CHAR; int m_NeedleSize; DFA_t m_DFA; }; const int KMP::TOTAL_CHAR = 256;
leetcode上測試相比暴力字串查詢方法速度快了近10倍
每個字母匹配分三種情況:
- 匹配到對應字元,模式指標j指向下一個位置.即j+=1;
- 沒有匹配到對應字元,但是匹配到公共字元字首.這種情況下,根據在公共字元字首中的位置決定模式指標指向的位置
- 沒有匹配到公共字元字首,這種情況下直接移動模式指標j到模式字串開頭,重新開始匹配
根據上述構建DFA的函式KMP::KMP()
可知構造時間複雜度為O(KMP::TOTAL_CHAR * M),空間複雜度為O(KMP::TOTAL_CHAR * M)
M表示模式匹配字串的長度
KMP演算法的優點是對於相同的模式字串,只需要構造一次DFA矩陣
缺點是比較大的空間複雜度
查詢函式KMP::SearchIn
時間複雜度為O(N),空間複雜度為O(1)。
綜合看來完全匹配一次時間複雜度為O(KMP::TOTAL_CHAR * M + N),空間複雜度為O(KMP::TOTAL_CHAR * M)