力扣28题:使用Java实现KMP算法找出字符串中第一个匹配项的下标


引言

LeetCode第28题要求实现一个函数,找出在一个字符串(主串)中第一次出现另一个字符串(模式串)的下标。KMP算法是解决这个问题的理想选择,因为它在最坏情况下也能提供线性时间复杂度的性能。本文将详细介绍KMP算法的原理,并展示如何用Java实现它。

KMP(Knuth-Morris-Pratt)算法是一种高效的字符串搜索(或模式匹配)算法,由Donald Knuth、Vaughan Pratt和James H. Morris于1977年共同发明。它的核心思想是当模式串(pattern)与主串(text)不匹配时,利用已经部分匹配的信息,避免从头开始匹配,从而提高匹配效率。

KMP算法原理详解

1. 部分匹配表(也称为前缀函数或失败函数)

KMP算法首先对模式串进行预处理,生成一个部分匹配表(π数组),该表记录了模式串中每个位置之前的子串中,有多少个字符是既匹配前缀也匹配后缀的。

例如,对于模式串"ABCDAB",在位置5(字符’B’)的π值是3,因为"CDAB"的前缀"CDA"和后缀"DA"有3个字符是相同的。

2. 搜索过程

在搜索过程中,KMP算法使用两个指针,分别指向主串和模式串的当前位置。当遇到匹配的字符时,两个指针同时向后移动;当遇到不匹配的字符时,根据π数组的值调整模式串的指针位置,而不是主串的指针。

3. π数组的计算

π数组的计算是KMP算法的第一步,以下是计算π数组的步骤:

  1. 初始化π[0]为0,因为没有任何字符之前,没有相同的前缀和后缀。
  2. 初始化两个指针i和j。i用于遍历模式串,j用于跟踪相同前缀和后缀的最长长度。
  3. 当模式串的第i个字符与第j个字符相同时,增加j,同时π[i] = j。
  4. 如果第i个字符与第j个字符不匹配,且j不为0,将j更新为π[j-1],因为可以假设模式串的前j-1个字符是匹配的。
  5. 如果j为0,且第i个字符与之前的任何字符都不匹配,那么π[i] = 0,并将i加1。

4. 匹配过程

  1. 初始化两个指针,分别指向主串和模式串的起始位置。
  2. 比较两个指针所指向的字符,如果相等,移动到下一个字符。
  3. 如果字符不匹配:
    • 使用π数组找到模式串中可以跳过的最远位置。这通常是π[j-1],除非j为0,在这种情况下,指针i加1,继续匹配。
    • 移动模式串的指针到这个新位置,然后继续比较。
  4. 如果模式串的指针到达模式串的末尾,记录当前主串指针的位置,这表示找到了一个匹配。

5. 优点

KMP算法的主要优点是它消除了在主串中的无效搜索,因为它利用了模式串的内部信息来决定下一步的搜索位置。这使得KMP算法在最坏情况下也能保持线性时间复杂度O(n+m),其中n是主串的长度,m是模式串的长度。

KMP算法的Java实现

1.KMP搜索算法

private void getNext(int[] next, String s) {
        int j = 0;
        next[0] = 0;
        for (int i = 1; i < s.length(); i++) {
            while (j > 0 && s.charAt(j) != s.charAt(i)) 
                j = next[j - 1];
            if (s.charAt(j) == s.charAt(i)) 
                j++;
            next[i] = j; 
        }
    }

2. 测试代码

class Solution {
    //前缀表(不减一)Java实现
    public int strStr(String haystack, String needle) {
        if (needle.length() == 0) return 0;
        int[] next = new int[needle.length()];
        getNext(next, needle);

        int j = 0;
        for (int i = 0; i < haystack.length(); i++) {
            while (j > 0 && needle.charAt(j) != haystack.charAt(i)) 
                j = next[j - 1];
            if (needle.charAt(j) == haystack.charAt(i)) 
                j++;
            if (j == needle.length()) 
                return i - needle.length() + 1;
        }
        return -1;

    }

结论

KMP算法是一种强大的字符串搜索工具,它通过预处理模式串来避免在主串中的无效搜索。通过本文的介绍,我们学习了KMP算法的原理和Java实现,以及如何在LeetCode第28题中应用它来找出字符串中第一个匹配项的下标。

扩展阅读

希望本文能够帮助读者深入理解KMP算法,并在实际编程中熟练应用。


  • 40
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值