置顶

讨论KMP.3 match[j] 的另一种定义

陈越 发表于2022年12月15日
<p>如果将 match[j] 定义为 pattern[0...j] 首尾匹配子串的最大长度,该如何修改 KMP 和 BuildMatch 的实现?</p>
89 回复

    1楼

  • 君子立命-一生无悔 发表于2023年05月21日
    0 | 0 | 举报
    <p>要让 KMP 函数返回模式在文本中的子串,可以修改函数的返回类型为字符串类型。同时,在 KMP 函数内部要记录子串在文本中的起始和终止下标,然后返回这个子串。下面是一个简单的修改版本:</p><p><br ></p><p><br ></p><p>#include &lt;iostream&gt;</p><p>#include &lt;cstring&gt;</p><p>using namespace std;</p><p><br ></p><p>string KMP(string text, string pattern)</p><p>{</p><p>&nbsp; &nbsp; int tlen = text.size();</p><p>&nbsp; &nbsp; int plen = pattern.size();</p><p>&nbsp; &nbsp; int fail[plen + 1];</p><p>&nbsp; &nbsp; memset(fail, -1, sizeof(fail));</p><p><br ></p><p>&nbsp; &nbsp; for (int j = 1; j &lt; plen; ++j) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; int i = fail[j - 1];</p><p>&nbsp; &nbsp; &nbsp; &nbsp; while (pattern[j] != pattern[i + 1] &amp;&amp; i &gt;= 0) i = fail[i];</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if (pattern[j] == pattern[i + 1]) fail[j] = i + 1;</p><p>&nbsp; &nbsp; }</p><p><br ></p><p>&nbsp; &nbsp; int i = 0, j = 0;</p><p>&nbsp; &nbsp; while (i &lt; tlen &amp;&amp; j &lt; plen) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if (text[i] == pattern[j]) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++i; ++j;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; } else if (j == 0) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++i;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j = fail[j - 1] + 1;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; }</p><p>&nbsp; &nbsp; }</p><p><br ></p><p>&nbsp; &nbsp; if (j == plen) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return text.substr(i - plen, plen);</p><p>&nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return &quot;not found&quot;;</p><p>&nbsp; &nbsp; }</p><p>}</p><p><br ></p><p>int main()</p><p>{</p><p>&nbsp; &nbsp; string text = &quot;ABCABCABCABD&quot;;</p><p>&nbsp; &nbsp; string pattern = &quot;ABCABD&quot;;</p><p>&nbsp; &nbsp; cout &lt;&lt; KMP(text, pattern) &lt;&lt; endl; // output: ABCABD</p><p>&nbsp; &nbsp; return 0;</p><p>}</p><p><br ></p><p>在 main 函数里,我们用 cout 输出 KMP 函数返回的字符串。这样,就可以在调用 KMP 函数后方便地输出子串了。</p><p><br ></p><p><br ></p><p><br ></p><p><br ></p><p><br ></p><p>riqilang wu</p><p>如果将 match[j] 定义为 pattern[0...j] 首尾匹配子串的最大长度,该如何修改 KMP 和 BuildMatch 的实现?</p><p>如果将 match[j] 定义为 pattern[0...j] 首尾匹配子串的最大长度,可以按照以下步骤完成 KMP 函数和 BuildMatch 函数的实现:</p><p><br ></p><p><br ></p><p><br ></p><p><br ></p><p>在 KMP 函数中,对于所有 j &lt; plen, match[j] 的值就是 fail[j] 的值加一(由于 fail 数组存储的是最后一个字符的最长公共前后缀长度,因此需要加一)。</p><p><br ></p><p><br ></p><p><br ></p><p><br ></p><p>BuildMatch 函数的实现也要相应地改变。在计算 fail 数组的过程中,可以顺便求出 match 数组的元素值。具体来说,只需要在 if (pattern[j] == pattern[i + 1]) 的分支中添加 match[j] = match[i] + 1; 的语句即可。</p><p><br ></p><p><br ></p><p><br ></p><p><br ></p><p>下面是 KMP 函数和 BuildMatch 函数的修改版本:</p><p><br ></p><p><br ></p><p>void BuildMatch(string pattern, int* fail, int* match)</p><p>{</p><p>&nbsp; &nbsp; int plen = pattern.size();</p><p>&nbsp; &nbsp; fail[0] = -1;</p><p>&nbsp; &nbsp; match[0] = -1;</p><p><br ></p><p>&nbsp; &nbsp; for (int j = 1; j &lt; plen; ++j) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; int i = fail[j - 1];</p><p>&nbsp; &nbsp; &nbsp; &nbsp; while (pattern[j] != pattern[i + 1] &amp;&amp; i &gt;= 0) i = fail[i];</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if (pattern[j] == pattern[i + 1]) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fail[j] = i + 1;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match[j] = match[i] + 1;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fail[j] = -1;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; match[j] = -1;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; }</p><p>&nbsp; &nbsp; }</p><p>}</p><p><br ></p><p>int KMP(string text, string pattern)</p><p>{</p><p>&nbsp; &nbsp; int tlen = text.size();</p><p>&nbsp; &nbsp; int plen = pattern.size();</p><p>&nbsp; &nbsp; int fail[plen], match[plen];</p><p>&nbsp; &nbsp; memset(fail, -1, sizeof(fail));</p><p>&nbsp; &nbsp; memset(match, -1, sizeof(match));</p><p><br ></p><p>&nbsp; &nbsp; BuildMatch(pattern, fail, match);</p><p><br ></p><p>&nbsp; &nbsp; int i = 0, j = 0;</p><p>&nbsp; &nbsp; while (i &lt; tlen &amp;&amp; j &lt; plen) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; if (text[i] == pattern[j]) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++i; ++j;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; } else if (j == 0) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++i;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j = fail[j - 1] + 1;</p><p>&nbsp; &nbsp; &nbsp; &nbsp; }</p><p>&nbsp; &nbsp; }</p><p><br ></p><p>&nbsp; &nbsp; if (j == plen) {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return match[j - 1];</p><p>&nbsp; &nbsp; } else {</p><p>&nbsp; &nbsp; &nbsp; &nbsp; return -1;</p><p>&nbsp; &nbsp; }</p><p>}</p><p><br ></p><p>在 KMP 函数中,我们新增了一个 match 数组来存储首尾匹配子串的最大长度。BuildMatch 函数在计算 fail 数组的同时,顺便计算 match 数组的元素值。在调用 KMP 函数时,我们得到的匹配结果就是首尾匹配子串的最大长度,如果匹配失败则返回 -1。</p><p><br ></p>
    君子立命-一生无悔 发表于2023年05月21日
    添加评论
  • 2楼

  • mooc86878792789389863 发表于2023年05月21日
    0 | 0 | 举报
    通过学习该门课程,我学习到了很多有关于该门课程的知识,很大程度上提升的我对该领域的兴趣,加强了课外兴趣,培养了创新能力,学到了很多知识,收获颇多!!!!
    mooc86878792789389863 发表于2023年05月21日
    添加评论
  • 3楼

  • mooc86878792789389863 发表于2023年05月21日
    0 | 0 | 举报
    通过学习该门课程,我学习到了很多有关于该门课程的知识,很大程度上提升的我对该领域的兴趣,加强了课外兴趣,培养了创新能力,学到了很多知识,收获颇多!!!!
    mooc86878792789389863 发表于2023年05月21日
    添加评论
  • 4楼

  • 黄超林cqvie 发表于2023年05月22日
    0 | 0 | 举报
    嗯...
    黄超林cqvie 发表于2023年05月22日
    添加评论
  • 5楼

  • 黄超林cqvie 发表于2023年05月22日
    0 | 0 | 举报
    嗯...
    黄超林cqvie 发表于2023年05月22日
    添加评论
  • 6楼

  • moocixxish 发表于2023年05月22日
    0 | 0 | 举报
    1
    moocixxish 发表于2023年05月22日
    添加评论
  • 7楼

  • 何兆乾 发表于2023年05月22日
    0 | 0 | 举报
    1
    何兆乾 发表于2023年05月22日
    添加评论
  • 8楼

  • 帅朕潇 发表于2023年05月22日
    0 | 0 | 举报
    1
    帅朕潇 发表于2023年05月22日
    添加评论
  • 9楼

  • 15班杨铭 发表于2023年05月22日
    0 | 0 | 举报
    1
    15班杨铭 发表于2023年05月22日
    添加评论
  • 10楼

  • 夜宇声烦mooc 发表于2023年05月23日
    0 | 0 | 举报
    1
    夜宇声烦mooc 发表于2023年05月23日
    添加评论
  • 11楼

  • mooc130444384387113904 发表于2023年05月23日
    0 | 0 | 举报
    1
    mooc130444384387113904 发表于2023年05月23日
    添加评论
  • 12楼

  • 刘洋19S070304060 发表于2023年05月23日
    0 | 0 | 举报
    1
    刘洋19S070304060 发表于2023年05月23日
    添加评论
  • 13楼

  • mooc143872449216063678 发表于2023年05月23日
    0 | 0 | 举报
    1
    mooc143872449216063678 发表于2023年05月23日
    添加评论
  • 14楼

  • mooc马琦 发表于2023年05月23日
    0 | 0 | 举报
    1
    mooc马琦 发表于2023年05月23日
    添加评论
  • 15楼

  • 学员8339kada129507580942547356 发表于2023年05月23日
    0 | 0 | 举报
    1
    学员8339kada129507580942547356 发表于2023年05月23日
    添加评论
  • 16楼

  • 帅朕潇 发表于2023年05月23日
    0 | 0 | 举报
    1
    帅朕潇 发表于2023年05月23日
    添加评论
  • 17楼

  • mooc84605028317236813 发表于2023年05月23日
    0 | 0 | 举报
    1
    mooc84605028317236813 发表于2023年05月23日
    添加评论
  • 18楼

  • NJUPTB22170210周雅洋 发表于2023年05月23日
    0 | 0 | 举报
    通过学习该门课程,我学习到了很多有关于该门课程的知识,很大程度上提升的我对该领域的兴趣,加强了课外兴趣,培养了创新能力,学到了很多知识,收获颇多!!!!
    NJUPTB22170210周雅洋 发表于2023年05月23日
    添加评论
  • 19楼

  • NJUPTB22170210周雅洋 发表于2023年05月23日
    0 | 0 | 举报
    通过学习该门课程,我学习到了很多有关于该门课程的知识,很大程度上提升的我对该领域的兴趣,加强了课外兴趣,培养了创新能力,学到了很多知识,收获颇多!!!!
    NJUPTB22170210周雅洋 发表于2023年05月23日
    添加评论
  • 20楼

  • mooc130444384387113904 发表于2023年05月23日
    0 | 0 | 举报
    通过学习该门课程,我学习到了很多有关于该门课程的知识,很大程度上提升的我对该领域的兴趣,加强了课外兴趣,培养了创新能力,学到了很多知识,收获颇多!!!!
    mooc130444384387113904 发表于2023年05月23日
    添加评论
点击加载更多