数据结构—串

文章介绍了KMP算法的核心思想,即避免在字符串匹配过程中不必要的回溯,通过构造next数组来确定模式串失配时的回退位置。next数组记录了模式串中每个位置前缀和后缀的最长公共长度,用于优化匹配过程。文中还提供了next数组的生成及KMP算法的实现代码。
摘要由CSDN通过智能技术生成

目录

基本介绍

KMP模式匹配算法

next 数组

优化next

手写 KMP 算法


基本介绍

  1. 串是由零个或多个字符组成的有限序列,又叫做字符串。

  2. 零个字符的串称为 空串

  3. 空格串:是只包含空格的串。它与空串是有区别的,空格串是有内容有长度的。

  4. 串中任意个数的连续字符组成的子序列称为该串的子串,相应的,包含子串的串称为主串

  5. 子串在主串中的位置就是子串的第一个字符在主串中的序号。

  6. 串也是一种数据结构,串所针对的是字符集,也就是串中的元素都是字符!

  7. 子串的定位操作通常称作串的模式匹配,应该算是串中最重要的操作之一。

KMP模式匹配算法

核心:KMP的next数组简单来说,假设有两个字符串,一个是待匹配的字符串strText,一个是要查找的关键字strKey。现在我们要在strText中去查找是否包含strKey,用i来表示strText遍历到了哪个字符,用j来表示strKey匹配到了哪个字符。

如果是暴力的查找方法,当 strText[i] 和 strKey[j] 匹配失败的时候,i 和 j 都要回退,然后从 i-j 的下一个字符开始重新匹配。

而KMP就是保证 i 永远不回退,只回退 j 来使得匹配效率有所提升。它用的方法就是利用strKey在失配的 j 为之前的成功匹配的子串的特征来寻找 j 应该回退的位置。而这个子串的特征就是前后缀的相同程度所以next数组其实就是查找strKey中每一位前面的子串的前后缀有多少位匹配,从而决定j失配时应该回退到哪个位置

前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

next 数组

  public static int[] getNext(String ps)
{
    char[] strKey = ps.toCharArray();
    int[] next = new int[strKey.length];

    // 初始条件
    int j = 0;
    int k = -1;
    next[0] = -1;//next 数组第一位默认为 -1,即让 i 右移
 
    // 根据已知的前j位推测第j+1位
    while (j < strKey.length - 1)
    {
        if (k == -1 || strKey[j] == strKey[k])
        {
            next[++j] = ++k;
        }
        else
        {
            k = next[k];
        }
    }

     return next;
}

优化next

 

public static int[] getNext(String ps)
{
    char[] strKey = ps.toCharArray();
    int[] next = new int[strKey.length];

    // 初始条件
    int j = 0;
    int k = -1;
    next[0] = -1;
 
    // 根据已知的前j位推测第j+1位
    while (j < strKey.length - 1)
    {
        if (k == -1 || strKey[j] == strKey[k]){
            // 如果str[j + 1] == str[k + 1],回退后仍然失配,所以要继续回退
            if (strKey[j + 1] == strKey[k + 1])
            {
                next[++j] = next[++k];
            }
            else
            {
                next[++j] = ++k;
            }
        }
        else
        {
            k = next[k];
        }
    }

     return next;
}

手写 KMP 算法

public static int KMP(String ts, String ps) {

    char[] t = ts.toCharArray();

    char[] p = ps.toCharArray();

    int i = 0; // 主串的位置

    int j = 0; // 模式串的位置

    int[] next = getNext(ps);

    while (i < t.length && j < p.length) {

       if (j == -1 || t[i] == p[j]) { // 当j为-1时,要移动的是i,当然j也要归0

           i++;

           j++;

       } else {

           // i不需要回溯了

           // i = i - j + 1;

           j = next[j]; // j回到指定位置

       }

    }

    if (j == p.length) {

       return i - j;

    } else {

       return -1;

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值