基于C#实现KMP算法

news2024/11/17 9:53:05

一、BF 算法

如果让你写字符串的模式匹配,你可能会很快的写出朴素的 bf 算法,至少问题是解决了,我想大家很清楚的知道它的时间复杂度为 O(MN),原因很简单,主串和模式串失配的时候,我们总是将模式串的第一位与主串的下一个字符进行比较,所以复杂度高在主串每次失配的时候都要回溯。

二、KMP 算法

刚才我们也说了,主串每次都要回溯,从而提高了时间复杂度,那么能不能在“主串”和“模式串”失配的情况下,主串不回溯呢?而是让”模式串“向右滑动一定的距离,对上号后继续进行下一轮的匹配,从而做到时间复杂度为 O(M+N)呢?所以 kmp 算法就是用来处理这件事情的,下面我们看下简单的例子。
image.png
通过这张图,我们来讨论下它的一般推理,假设主串为 S,模式串为 P,在 Si != Pj 的时候,我们可以看到满足如下关系式 Si-jSi-j+1…Sn-1=P0P1…Pj-1。
那么模式 P 应该向右滑动多少距离?也就是主串中的第 i 个字符应与模式串中的哪一个字符进行比较?
假设应该与模式串中的第 k 的位置相比较,假如模式串中存在最大的前缀真子串和后缀真子串,那么有 P0P1…Pk-1=Pj-kPj-k+1…Pj-1.
这句话的意思也就是说,在模式 P 中,前 k 个字符与 j 个字符之前的 k 个字符相同,比如说:“abad”的最大前缀真子串为“aba",最大后缀真子串为“bad”,当然这里是不相等,这里的 0<k<j,我们希望 k 接近于 j,那么我们滑动的距离将会最小,好吧,现在我们用 next[j]来记录失配时模式串应该用哪一个字符于 Si 进行比较。
设 next[j]=k。根据公式我们有

next[j] =  -1     当 j=0 时
next[j] =  max{k| 0<k<j 且 P0P1..Pk-1=Pj-kPj-k+1...Pj-1}
next[j] =  0     其他情况

好,接下来的问题就是如何求出 next[j],这个也就是 kmp 思想的核心,对于 next[j]的求法,我们采用递推法,现在我们知道了 next[j]=k,我们来求 next[j+1]=?的问题,其实也就是两种情况:
①:Pk=Pj 时 则 P0P1…Pk=Pj-kPj-k+1…Pj, 则我们知:

next[j+1]=k+1。

又因为 next[j]=k,则

next[j+1]=next[j]+1。

②:Pk!=Pj 时 则 P0P1…Pk!=Pj-kPj-k+1…Pj,其实这里我们又将模式串的匹配问题转化为了上面我们提到的”主串“和”模式串“中寻找 next 的问题,你可以理解成在模式串的前缀串和后缀串中寻找 next[j]的问题。现在我们的思路就是一定要找到这个 k2,使得 Pk2=Pj,然后将 k2 代入 ① 就可以了。
设 k2=next[k]。 则有 P0P1…Pk2-1=Pj-k2Pj-k2+1…Pj-1。
若 Pj=Pk2, 则 next[j+1]=k2+1=next[k]+1。
若 Pj!=Pk2, 则可以继续像上面递归的使用 next,直到不存在 k2 为止。
好,下面我们上代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SupportCenter.Test
{
  public class Program
  {
     static void Main(string[] args)
     {
         string zstr = "ababcabababdc";

         string mstr = "babdc";

         var index = KMP(zstr, mstr);

         if (index == -1)
             Console.WriteLine("没有匹配的字符串!");
         else
             Console.WriteLine("哈哈,找到字符啦,位置为:" + index);

         Console.Read();
     }

     static int KMP(string bigstr, string smallstr)
     {
         int i = 0;
         int j = 0;

         //计算“前缀串”和“后缀串“的next
         int[] next = GetNextVal(smallstr);

         while (i < bigstr.Length && j < smallstr.Length)
         {
             if (j == -1 || bigstr[i] == smallstr[j])
             {
                 i++;
                 j++;
             }
             else
             {
                 j = next[j];
             }
         }

         if (j == smallstr.Length)
             return i - smallstr.Length;

         return -1;
     }

     /// <summary>
     /// p0,p1....pk-1         (前缀串)
     /// pj-k,pj-k+1....pj-1   (后缀串)
     /// </summary>
     /// <param name="match"></param>
     /// <returns></returns>
     static int[] GetNextVal(string smallstr)
     {
         //前缀串起始位置("-1"是方便计算)
         int k = -1;

         //后缀串起始位置("-1"是方便计算)
         int j = 0;

         int[] next = new int[smallstr.Length];

         //根据公式: j=0时,next[j]=-1
         next[j] = -1;

         while (j < smallstr.Length - 1)
         {
             if (k == -1 || smallstr[k] == smallstr[j])
             {
                 //pk=pj的情况: next[j+1]=k+1 => next[j+1]=next[j]+1
                 next[++j] = ++k;
             }
             else
             {
                 //pk != pj 的情况:我们递推 k=next[k];
                 //要么找到,要么k=-1中止
                 k = next[k];
             }
         }

         return next;
     }
 }
}

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1234065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

做黄金代理可以代理什么品种?

近几年&#xff0c;黄金代理这个职业发展的比较迅猛&#xff0c;主要是受金融环境越来越稳定、金融投资越来越发达的大势所推动。那些有意想做黄金代理的朋友就会有疑问&#xff0c;做了黄金代理可以代理什么品种的&#xff1f; 其实广义上来说&#xff0c;黄金代理有很多种&am…

【Pytorch】Visualization of Feature Maps(1)

学习参考来自 CNN可视化Convolutional Featureshttps://github.com/wmn7/ML_Practice/blob/master/2019_05_27/filter_visualizer.ipynb 文章目录 filter 的激活值 filter 的激活值 原理&#xff1a;找一张图片&#xff0c;使得某个 layer 的 filter 的激活值最大&#xff0c…

C#核心笔记——(二)C#语言基础

一、C#程序 1.1 基础程序 using System; //引入命名空间namespace CsharpTest //将以下类定义在CsharpTest命名空间中 {internal class TestProgram //定义TestProgram类{public void Test() { }//定义Test方法} }方法是C#中的诸多种类的函数之一。另一种函数*&#xff0c;还…

机器学习介绍与分类

随着科学技术的不断发展&#xff0c;机器学习作为人工智能领域的重要分支&#xff0c;正逐渐引起广泛的关注和应用。本文将介绍机器学习的基本概念、原理和分类方法&#xff0c;帮助读者更好地理解和应用机器学习技术。 一、机器学习的基本概念 机器学习是一种通过从数据中学…

每日汇评:美日在两个月低点附近似乎较为脆弱,熊市可能会在FOMC会议纪要公布前暂停

美元/日元跌至两个月低点&#xff0c;并受到多种因素的压力&#xff1b; 美联储鸽派预期和美国债券收益率下降继续令美元承压&#xff1b; 美日利差缩小以及日本央行政策转变的押注提振了日元&#xff1b; 美元/日元货币对在周二持续第四天承受着沉重的卖压&#xff0c;同时也标…

Vue+Swiper实现轮播图效果

效果展示 实现了自带切换按钮在图片外部实现了自定义的切换按钮 背景 在项目中使用到了轮播图&#xff0c;实现点击上一张下一张时实现循环显示&#xff0c;同时预览两个图片&#xff0c;并加以文字对图片的说明。 设计 使用 Swiper 插件&#xff0c;可以实现当前这个需求。…

linux制作 ext4镜像image 脚本demo

结构如下&#xff1a; build_linux_targetfs.sh #!/bin/bashCHECK_MARK"\033[0;32m\xE2\x9C\x94\033[0m" X_MARK"\033[0;1;31mX\033[0m"export TOP_DIR$PWD export TARGET_IMAGE_PATH$TOP_DIR/filesystem/targetfs-images export BSP_IMAGE_PATH${TOP_DI…

数据库表的内连接和外连接

1.内连接查询语法 -- 隐式内链接 SELECT 字段列表 FROM 表1&#xff0c;表2WHERE 条件&#xff1b; -- 显示内连接 select 字段列表 from 表1 [inner] join 表2 on 条件&#xff1b; 如果两个表没用进行内连接&#xff0c;会生成笛卡尔积。A集合和B集合全部元素进行排列组合。 …

关于校园网使用罗技flow功能

目录 情况概述问题及解决方案 情况概述 我目前设备是一台Macbook air m1处理器&#xff0c;学校给配了一台windows台式&#xff0c;台式机不能连蓝牙&#xff0c;不能连wifi&#xff0c;只能用网线&#xff0c;我的需求是想让mac和windows共用一套键鼠&#xff0c;在了解到罗技…

万宾科技智能井盖的效果怎么样?

日常出行过程中&#xff0c;人们最不想看到交通拥堵或者道路维修等现象&#xff0c;因为这代表出行受到影响甚至会导致不能按时赴约等。所以城市路面的安全和稳定&#xff0c;是市民朋友非常关心的话题。骑行在路上的时候&#xff0c;如果经过井盖时发出异常声响&#xff0c;骑…

福州大学《嵌入式系统综合设计》实验四:边缘检测

一、实验目的 BMCV 提供了一套基于 Sophon AI 芯片优化的机器视觉库&#xff0c;通过利用芯片的 TPU 和 VPP模块&#xff0c;可以完成色彩空间转换、尺度变换、仿射变换、透射变换、线性变换、画框、JPEG 编解码、BASE64 编解码、NMS、排序、特征匹配等操作。 本实验的目的是…

navicat --CSV导出数据乱码情况(三种情况解决方式)

CSV导出数据乱码情况分析及处理 在navicat 中有很多导出方式&#xff0c;大家都知道csv导出要比xlse要快很多&#xff0c;但是在使用csv导出时要防止乱码情况&#xff0c; 下面我列出三种处理方式&#xff08;如有其他方式大家可以帮忙补充一下&#xff09;&#xff1a; 文章目…

使用Python的Turtle库绘制一个心形图像(含详细Python代码与注释)

1.1引言&#xff1a; Python的Turtle库是一个非常实用的图形绘制库&#xff0c;它让我们可以使用简单的命令来绘制各种图形。这个库特别适合用来绘制几何图形&#xff0c;尤其是那些需要精细控制的图形。在本博客中&#xff0c;我们将使用Turtle库来绘制一个具体的图形。 1.2…

如何验证命令执行漏洞(无回显)

如何验证命令执行漏洞&#xff08;无回显&#xff09; 使用yakit&#xff0c;选择dnslog模块 点击生成一个可用域名 以dvwa为例 命令执行ping一下刚才的域名 随后yakit中会出现回显信息&#xff0c;以此证明拥有命令执行漏洞 信息&#xff0c;以此证明拥有命令执行漏洞

WMS系统先验后收策略

在制造业工厂的仓库管理中&#xff0c;确保物料的质量和数量是至关重要的。传统的仓库管理方式往往采用“先收后验”策略&#xff0c;即先接收物料&#xff0c;然后再进行质量检验。然而&#xff0c;这种方式存在一定的风险&#xff0c;例如不良品流入、数量不准确等问题。为了…

洛谷 P4568 [JLOI2011] 飞行路线 pytho解析

P4568 [JLOI2011] 飞行路线 pytho解析 时间&#xff1a;2023.11.20 题目地址&#xff1a;[JLOI2011] 飞行路线 题目分析 对于这个题呢就是最短路的问题了。那就可以用Dijkstra 算法&#xff0c;唯一不同的地方就是有免费的机票次数&#xff0c;那我们就先不考虑这个&#xf…

HTML+CSS+ElementUI搭建个人博客页面(纯前端)

网站演示 搭建过程 html部分 首先下载Vue2&#xff0c;ElementUI等插件&#xff0c;放在你的本地。我这里为了运行方便&#xff0c;把代码放在了一个框架里运行。 下载后引入部分 <link rel"stylesheet" href"{{URL::asset(elementui/lib/theme-chalk/ind…

最新最全系列之Selenium:传入webdriver驱动的新方法 Service()函数;以前的executable_path报警告,即将弃用

传入webdriver驱动的新方法 Service()函数&#xff1b;以前的executable_path报警告&#xff0c;即将弃用 以前的方法 举例&#xff1a;webdriver.Chrome(executable_pathdriver_path)&#xff1b;看提示警告&#xff0c;提示该方法即将被弃用&#xff1b;如下图&#xff1a; …

vue项目中element-ui对话框el-dialog嵌套显示时多了一个遮罩层解决办法

在对话框里又嵌套了一个对话框展示时&#xff0c;多了一个遮罩层&#xff0c;如下图所示&#xff1a; 解决办法如下&#xff1a; 给对话框添加append-to-body 属性&#xff0c;参考以下代码&#xff1a; <el-dialog :visible.sync"dialogVisible" append-to-body …