LeetCode_0028. 找出字符串第一个匹配项的下标,KMP算法的实现

题目描述

  给你两个字符串 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;
    }
posted @ 2024-09-03 16:14  某糕  阅读(5)  评论(0编辑  收藏  举报