KMP算法

本文详细介绍了KMP算法中的next数组概念,包括前缀和后缀的定义,以及它们在求解next数组中的特殊性。提供了一个Java实现的next数组计算代码,并展示了如何使用KMP算法进行字符串匹配,以及如何找到文本串中所有模板串出现的次数。此外,还讨论了如何在KMP算法中处理特殊情况,如需寻找文本串中的所有模板串出现。
摘要由CSDN通过智能技术生成

next数组相关概念

借助算法导论的一段话解释前缀和后缀的含义。
在这里插入图片描述
举个例子,假设有字符串“abcd”,那么
1、前缀:a,ab,abc,abcd,
2、后缀:d,cd,bcd,abcd,
当然空串即是前缀也是后缀。
但是在求解next数组中的前缀和后缀时,前缀是不包含末尾的那一个字符,后缀不包含首位字符,这是因为如果包含的情况下,那么前缀和后缀的最长公共子串永远就是字符串本身。

这里声明一下:模式串从下标0开始,因此next[0] = -1,如果模式串从下标1开始,那么next数组所有元素加1。
next数组:当主串与模式串的某一个不匹配时,模式串回退的位置,比如当前主串的j位与模式串的i位不匹配,那么下一次就从模式串的next[i]位与主串的j位开始匹配。
next[i]:表示模式串的前i个字符(即0~i-1)的前缀和后缀的最长公共子串数。

这里是采用字符串下标从1开始分析。
在这里插入图片描述
在这里插入图片描述
求next数组的代码:next数组的第0个元素以-1开始。

  public int[] getNext(String str) {
        int[] next = new int[str.length()];
        //初始化next
        next[0] = -1;
        int i = 0;
        int j = -1;
        while(i < str.length()-1) {
            if(j == -1 || str.charAt(i) == str.charAt(j)) {
               i++;
               j++;
               next[i] = j;
            } else {
               j = next[j];
            }
        }
        return next;
    }

KMP匹配算法

//str1是文本串,str2是模板串,next是str2的next数组
 public int KMP(String str1,String str2,int[] next) {
 		//标记str1的匹配位置
        int i = 0;
        //标记str2的匹配位置
        int j = 0;
        
        while(i < str1.length()) {
        //如果当前要匹配的位置加上模板串的剩余部分超过了文本串的长度,那么说明后面不可能在有匹配串
            if(i + str2.length() - j - 1>= str1.length()) {
                return -1;
            }
            //如果文本串的第i位与模板串的第j位匹配,那么匹配下一位字符
            if(str1.charAt(i) == str2.charAt(j)) {
                i++;
                j++;
                //如果模板串匹配完成,说明完成了一次匹配,返回模板串在文本串的起始位置
                if(j == str2.length()) {
                    return i - j;
                }

            } else {
            //如果当前文本串的第i位与模板串的第j位不匹配,那么让模板串的next[j]位与文本串的第i位进行匹配
                j = next[j];
                //如果j= -1,说明文本串的第i+1位开始与模板串的第0位开始匹配
                if(j == -1) {
                    i++;
                    j++;
                }
            }
        }
        return -1;
    }

变形:如何找出文本串中所有的模板串?
假设文本串“abababab”,模板串“abab”,那么第一次匹配完成是在文本串的第3位和模板串的第3位(下标从0开始),这种情况我们需要找到文本串的“abab”的最长公共前后缀,即next[4],在上面的求next数组的算法中,发现并没有求next[str.length],因此这里只需要求出让next数组长度为模板串的长度加1

牛客中的一道KMP算法:
在这里插入图片描述

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 计算模板串S在文本串T中出现了多少次
     * @param S string字符串 模板串
     * @param T string字符串 文本串
     * @return int整型
     */
    public int kmp (String S, String T) {
        int[] next = getNext(S);
         //System.out.println(next.length);
        int i = 0;
        int j = 0;
        int counter = 0;
        while(i < T.length()) {
            if(i + S.length() - j - 1>= T.length()) {
                return counter;
            }
            if(T.charAt(i) == S.charAt(j)) {
                i++;
                j++;
                if(j == S.length()) {
                    counter++;
                   // System.out.println("开始位置:"+(i-j));
                    j = next[j];
                }

            } else {
                j = next[j];
                if(j == -1) {
                    i++;
                    j++;
                }
            }
        }
     return counter;
    }
      public int[] getNext(String str) {
        int[] next = new int[str.length() + 1];
        //初始化next
        next[0] = -1;
        int i = 0;
        int j = -1;
        while(i < str.length()) {
            if(j == -1 || str.charAt(i) == str.charAt(j)) {
               i++;
               j++;
               next[i] = j;
            } else {
               j = next[j];
            }
        }
        return next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值