C#利用KPM算法解决字符串匹配问题详解

 更新时间:2022年11月18日 11:15:33   作者:黑夜中的潜行者  
Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现位置。本文将利用该算法解决字符串匹配问题,感兴趣的可以学习一下

什么是KPM算法

Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现位置,这个算法由Donald Knuth、Vaughan Pratt、James H. Morris三人于1977年联合发表,故取这3人的姓氏命名此算法。

KMP方法算法就利用之前判断过信息,通过一个next数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过next数组找到,前面匹配过的位置,省去了大量的计算时间。

KPM的使用场景:模式串在文本串是否出现过,如果出现过,最早出现的位置

步骤

Ⅰ根据《最大长度表》部分匹配表(next)

对于P = p0 p1 ...pj-1 pj,寻找模式串P中长度最大且相等的前缀和后缀。如果存在p0 p1 ...pk-1 pk = pj- k pj-k+1...pj-1 pj,那么在包含pj的模式串中有最大长度为k+1的相同前缀后缀。

举个例子,如果给定的模式串为“abab”,那么它的各个子串的前缀后缀的公共元素的最大长度如下表格所示:

比如对于字符串aba来说,它有长度为1的相同前缀后缀a;而对于字符串abab来说,它有长度为2的相同前缀后缀ab(相同前缀后缀的长度为k + 1,k + 1 = 2)。

结论:最大前缀后缀元素长度所得到的数组就是我们所需要的 “部分匹配表”

寻找最长前缀后缀

如果给定的模式串是:“ABCDABD”,从左至右遍历整个模式串,其各个子串的前缀后缀分别如下表格所示:

Ⅱ 根据 部分匹配表 进行匹配

匹配失配,j = next [j],模式串向右移动的位数为:j - next[j]。换言之,当模式串的后缀pj-k pj-k+1, ..., pj-1跟文本串si-k si-k+1, ..., si-1匹配成功,但pj跟si匹配失败时,因为next[j] = k,相当于在不包含pj的模式串中有最大长度为k 的相同前缀后缀,即p0 p1 ...pk-1 = pj-k pj-k+1...pj-1,故令j = next[j],从而让模式串右移j - next[j]位,使得模式串的前缀p0 p1, ..., pk-1对应着文本串si-k si-k+1, ..., si-1,而后让pk跟si继续匹配。如下图所示:

KMP的next数组相当于告诉我们:

当模式串中的某个字符跟文本串中的某个字符匹配失配时,模式串下一步应该跳到哪个位置。如模式串中在j处的字符跟文本串在i处的字符匹配失配时,下一步用next [j]处的字符继续跟文本串i 处的字符匹配,相当于模式串向右移动j - next[j]位。

代码实现

字符串匹配问题:

有一个字符串 str1=““上海自来水来自海上””,和一个子串 str2=“自来水”。

现在要判断str1是否含有str2, 如果存在,就返回第一次出现的位置, 如果没有,则返回-1

static void Main(string[] args)
{
    string str1 = "上海自来水来自海上";
    string str2 = "自来水";
	
	// 得出 部分匹配表
    int[] next = KPMNext(str2);
    // 根据 得出的 部分匹配表的 next 数组进行匹配,
    int index = KPMSearch(str1, str2, next);
    
    Console.WriteLine(index);
}

/// <summary>
/// 获取一个字符串的部分匹配值表
/// </summary>
/// <param name="dest"></param>
/// <returns></returns>
static int[] KPMNext(string dest)
{
    // 初始化 数组大小
    int[] next = new int[dest.Length];
    // 字符串长度为1,部分匹配值就为0
    next[0] = 0;
    for (int i = 1, j = 0; i < dest.Length; i++)
    {
        while (j > 0 && dest[i] != dest[j])
        {
            j = next[j - 1];
        }
        if (dest[i] == dest[j])
        {
            j++;
        }
        next[i] = j;
    }
    return next;
}

/// <summary>
/// kmp搜索
/// </summary>
/// <param name="str1">源字符串</param>
/// <param name="str2">子字符串</param>
/// <param name="next">部分匹配表</param>
/// <returns></returns>
static int KPMSearch(string str1, string str2, int[] next)
{
    for (int i = 0, j = 0; i < str1.Length; i++)
    {
        while (j > 0 && str1[i] != str2[j])
        {
            j = next[j - 1];
        }

        if (str1[i] == str2[j])
        {
            j++;
        }

        if (j == str2.Length)
        {
            return i - j + 1;
        }
    }
    return -1;
}

到此这篇关于C#利用KPM算法解决字符串匹配问题详解的文章就介绍到这了,更多相关C# KPM字符串匹配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#多态的三种实现方式(小结)

    C#多态的三种实现方式(小结)

    这篇文章主要介绍了C#多态的三种实现方式(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 利用MySqlBulkLoader实现批量插入数据的示例详解

    利用MySqlBulkLoader实现批量插入数据的示例详解

    MySQLBulkLoader是MySQL Connector/Net类中的一个类,用于包装MySQL语句。本文将利用MySqlBulkLoader实现批量插入数据功能,感兴趣的可以了解一下
    2022-06-06
  • C#实现打字小游戏

    C#实现打字小游戏

    这篇文章主要为大家详细介绍了C#实现打字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • 详解C#设计模式编程中的模板方法模式使用

    详解C#设计模式编程中的模板方法模式使用

    这篇文章主要介绍了C#设计模式编程中的模板方法模式,模板方法模式比较好理解,即设定好算法骨架以后进行代码的反复利用,需要的朋友可以参考下
    2016-02-02
  • Unity实现移动端手势解锁功能

    Unity实现移动端手势解锁功能

    这篇文章主要为大家详细介绍了Unity实现移动端手势解锁功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C#实现加密bat文件的示例详解

    C#实现加密bat文件的示例详解

    这篇文章主要为大家详细介绍了C#如何实现加密bat文件的功能,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-01-01
  • 详解C#如何提取PDF文档中的图片

    详解C#如何提取PDF文档中的图片

    提取图片可以将这些图像资源进行单独保存,方便后续在不同的项目中使用,下面我们就来看看如何使用C#通过代码从PDF文档中提取图片吧
    2025-04-04
  • C#自定义Attribute值的获取与优化技巧

    C#自定义Attribute值的获取与优化技巧

    C#自定义Attribute值的获取是开发中会经常用到的,大家通常使用反射进行获取的,代码也很简单,今天通过本文给大家讲解C# Attribute值获取方法,感兴趣的朋友跟随小编一起看看吧
    2023-07-07
  • C#使用Consul集群进行服务注册与发现

    C#使用Consul集群进行服务注册与发现

    这篇文章主要介绍了C#使用Consul集群进行服务注册与发现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • C#在DataTable中根据条件删除某一行的实现方法

    C#在DataTable中根据条件删除某一行的实现方法

    我们通常的方法是把数据源放在DataTable里面,但是偶尔也会需要把不要的行移除,怎么实现呢,下面通过代码给大家介绍c# atatable 删除行的方法,需要的朋友一起看下吧
    2016-05-05

最新评论