LeetCode_0028. 找出字串第一個匹配項的下標,KMP演算法的實現

某糕發表於2024-09-03

題目描述

  給你兩個字串 haystack 和 needle ,請你在 haystack 字串中找出 needle 字串的第一個匹配項的下標(下標從 0 開始)。如果 needle 不是 haystack 的一部分,則返回 -1 。

  • 示例 1:

    輸入:haystack = "sadbutsad", needle = "sad"
    輸出:0
    解釋:"sad" 在下標 0 和 6 處匹配。
    第一個匹配項的下標是 0 ,所以返回 0 。

  • 示例 2:

    輸入:haystack = "leetcode", needle = "leeto"
    輸出:-1
    解釋:"leeto" 沒有在 "leetcode" 中出現,所以返回 -1 。

  • 提示:

    1 <= haystack.length, needle.length <= 104
    haystack 和 needle 僅由小寫英文字元組成
    

KMP演算法

  字串匹配問題,設主串有m個字元,模式串有n個字元,暴力方法要時間O(mn)。KMP演算法透過求解next陣列,消除了失配時主串回溯步驟,使得時間複雜度降低到O(m+n)。

核心 —— next/nextval陣列

  當haystack[p]和needle[q]失配發生時,主串指標p不動,模式串指標q跳轉到nextval[q]與主串匹配。

分析模式串,求解next/nextval陣列

  • 先求next陣列

    next[i] = needle[0..i]的最長匹配前字尾的長度;

  • 推導nextval陣列

    nextval[0] = -1;
    nextval[i] = next[i-1];

  • 也可以一步到位,比如這個實現

    vector<int> nextval(n, 0);
    nextval[0] = -1;      // -1表示下一匹配中,主串指標p++, 模式串指標q=0
    for(int j = 0, k = -1; j < n - 1; ) {
      if(k == -1 || needle[j] == needle[k]) {
        ++k, ++j;
        nextval[j] = k;
      } else {
        k = next[k];      // point
      }
    }
    

匹配,返回第一次匹配模式串的下標

    int p = 0, q = 0;
    while(q < n && p < m) {
      if(haystack[p] == needle[q]) {
        ++p, ++q;
      } else {
        if(nextval[q] == -1) {
          ++p;
          q = 0;
        } else {
          q = nextval[q];
        }
      }
    }

    if(q == n) {
      return p - n;
    } else {
      return -1;
    }

相關文章