KMP (Knuth-Morris-Pratt Algorithm) アルゴリズムは、文字列から特定の部分文字列を見つけるための文字列マッチングに使用されます。しかし、それを理解して習得するのはそれほど簡単ではありません。部分一致テーブルの概念を理解することが、KMP アルゴリズムを理解する鍵となります。 ここでの議論は、その背後にあるあいまいなロジックを避け、その応用から理解することに焦点を当てています。 文字列検索たとえば、文字列 簡単な解決策です。
この単純なソリューションの欠点は、マッチングが失敗するたびにインデックスが 1 位置だけ戻されるため、冗長な操作が多く効率的ではないことです。 マッチングの最初のラウンド、つまりインデックスが 0 の場合、等しい最初の 4 文字 部分一致テーブル/部分一致テーブル長さ 8abababca <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">char: | a | b | a | b | a | b | c | a |<br>index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | <br>value: | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |</span> ログイン後にコピー ログイン後にコピー value サブセット上記の例の文字列の場合、index プレフィックスとサフィックス指定された文字列の末尾から 1 つ以上の文字を削除し、残りの部分を文字列プレフィックス (適切な) の真の値と呼びます。プレフィックス)、以下プレフィックスと呼びます。ここでの「真」は「真の接頭辞」を意味するものではなく、数学における集合の「適切な部分集合」を考えてください。たとえば、banana
、そのサフィックスは: ##ナナ<span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"></span> <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"></span>
<span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"></span>
<span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"></span> ##部分一致値すべてのプレフィックスとサフィックスが数量的に対称であることがわかります。次に、プレフィックスから 1 つを見つけて、それをサフィックスと照合します。この試合の意味。最初のテキスト abababca を例として取り上げます。
で、その接尾辞と接尾辞は次のようになります。
index
index
a で始まり、すべてのサフィックスがa bababca 如果匹配过程中,匹配到了部分值为 下面是本文开始时的那个部分匹配表: <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">char: | a | b | a | b | a | b | c | a |<br>index: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | <br>value: | 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 |</span> ログイン後にコピー ログイン後にコピー 假设需要从 首次匹配发生在总字符串的第二个字符, <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">bacbababaabcbab |<br> abababca</span> ログイン後にコピー 此时匹配的长度为 1,部分匹配表中索引为 1-1=0 的位置对应的部分匹配值为 0,所以我们可以向前移动的距离是 继续直到再次发生匹配,此时匹配到的情况如下: <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">bacbababaabcbab |||||<br> abababca</span> ログイン後にコピー 现在匹配到的长度是 5,部分匹配表中 5-1=4 对应的部分匹配值为 3,所以我们可以向前移动 5-3=2,此时一下子就可以移动两位了。 <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"> 上一次的位置 | 最新移动到的位置 | |bacbababaabcbab<br> xx|||<br> abababca</span> ログイン後にコピー 此时匹配到的长度为 3, 查找到 3-1=2。 <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">bacbababaabcbab<br> xx|<br> abababca</span> ログイン後にコピー 此时我们需要查找的字符串其长度已经超出剩余可用来匹配的字符串了,所以可直接结束匹配,得到结论:没有查找到结果。 Javascript 中的实现以下是来自 trekhleb/javascript-algorithms 中 JavaScript 版本的 KMP 算法实现: 相关教程:Javascript视频教程 <span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif">//**<br/> * @see https://www.youtube.com/watch?v=GTJr8OvyEVQ<br/> * @param {string} word<br/> * @return {number[]}<br/> */<br/>function buildPatternTable(word) {<br/> const patternTable = [0];<br/> let prefixIndex = 0;<br/> let suffixIndex = 1;<br/><br/> while (suffixIndex < word.length) {<br/> if (word[prefixIndex] === word[suffixIndex]) {<br/> patternTable[suffixIndex] = prefixIndex + 1;<br/> suffixIndex += 1;<br/> prefixIndex += 1;<br/> } else if (prefixIndex === 0) {<br/> patternTable[suffixIndex] = 0;<br/> suffixIndex += 1;</span><span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"><br/></span><span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"> } else {<br/> prefixIndex = patternTable[prefixIndex - 1];<br/> }<br/> }<br/><br/> return patternTable;<br/>}<br/><br/>/**<br/> * @param {string} text<br/> * @param {string} word<br/> * @return {number}<br/> */<br/>export default function knuthMorrisPratt(text, word) {<br/> if (word.length === 0) {<br/> return 0;</span><span style="font-family:Microsoft Yahei, Hiragino Sans GB, Helvetica, Helvetica Neue, 微软雅黑, Tahoma, Arial, sans-serif"><br/> }<br/><br/> let textIndex = 0;<br/> let wordIndex = 0;<br/><br/> const patternTable = buildPatternTable(word);<br/><br/> while (textIndex < text.length) {<br/> if (text[textIndex] === word[wordIndex]) {<br/> // We've found a match.<br/> if (wordIndex === word.length - 1) {<br/> return (textIndex - word.length) + 1;<br/> }<br/> wordIndex += 1;<br/> textIndex += 1;<br/> } else if (wordIndex > 0) {<br/> wordIndex = patternTable[wordIndex - 1];<br/> } else {<br/> wordIndex = 0;<br/> textIndex += 1;<br/> }<br/> }<br/><br/> return -1;<br/>}<br/></span> ログイン後にコピー 时间复杂度 因为算法中涉及两部分字符串的线性对比,其时间复杂度为两字符串长度之和,假设需要搜索的关键词长度为 k,总字符串长度为 m,则时间复杂度为 O(k+m)。 |
以上がKMPアルゴリズムを簡単に理解できるようにするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。