字符串匹配算法(BF&&KMP)

简介: 字符串匹配算法(BF&&KMP)

字符串匹配算法

在学习这个算法之前,我们先来看看什么时字符串匹配算法,简单来说有一个主串和一个子串,查找子串在主串的位置,然后返回这个位置的下标。

想要实现这个功能其实有很多方法,比较有名的算法有两种:一种是BF算法又称暴力算法,另一种就是KMF算法。


BF算法

BF算法:思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,如果相等,则继续比较S的第二个字符和T的第二个字符;如果不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的酦醅结果。

举个例子:

1.png


代码实现

#define _CRT_SECURE_NO_WARNINGS 1
//BF算法
#include<assert.h>
#include<stdio.h>
//str为主串,sub为子串
int BF(char* str, char* sub)
{
  assert(str != NULL && sub != NULL);
  if (str == NULL || sub == NULL)
  return -1;
  int lenStr = strlen(str);
  int lenSub = strlen(sub);
  int i = 0;
  int j = 0;
  while (i < lenStr && j < lenSub)
  {
  if (str[i] == sub[j])
  {
    i++;
    j++;
  }
  else
  {
    i = i - j + 1;
    j = 0;
  }
  }
  if (j >= lenSub)//如果j>=lenSub说明子串遍历完成,即匹配成功,返回i的下标。
  {
  return i - j;
  }
  //不存在直接返回-1
  return -1;
}
int main()
{
  printf("%d\n", BF("ababcabcdabcde", "abcd"));
  printf("%d\n", BF("ababcabcdabcde", "abcdf"));
  printf("%d\n", BF("ababcabcdabcde", "ab"));
  return 0;
}

2.png

KMP算法

KMP算法就是对BF算法是一种对BF算法的改进,该算法核心就是可以利用匹配失败后的信息,尽量减少模式串与字串的匹配次数以到达快速匹配的目的(具体shi)。

KMP与BF算法的区别就是KMP算法主串的并不会回退;并且j不会移动到0号位置,而是移动到一个特定的位置。

我们直接来举个例子:


3.png


此时i和j位置的字符不匹配了。此时i是不进行回溯的,而是要对j进行回溯,那么j应该回溯到哪个位置呢?

4.png

由于每个位置要回溯的位置可能不一样,所以就引出了next数组。即用next[j]=k来表示。不同的j对应一个K值。这个K就是将来j要进行回溯的位置。如上图我们求的是当j=5的时候,K的值就是2,即将来j要回溯到下标为2的位置。即next[5]=2;。再比如说,当j是4的时候,K的值就是1,即next[4]=1;。


5.png

关于K值求取的规则如下:


1.找到匹配成功部分的两个相等的真串(不包含本身),一个以下标0开始,另一个j-1下标结束。

2.无论是什么数据,如果我们是从0开始计数(这里按照数组下标从0开始的习惯所以从0开始计数),那么next[0]=-1;next[1]=0;如果我们从1开始计数,那么next[0]=0;next[1]=1。


来练习一下:

"a b a b c a b c d a b c d e ",求其next数组。

答案如下图:

6.png


代码实现

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
void GetNext(char* sub, int* next, int lenSub)
{
  next[0] = -1;
  next[1] = 0;
  int i = 2;
  int k = 0;
  while (i < lenSub)
  {
  if (k == -1 || sub[i - 1] == sub[k])
  {
    next[i] = k + 1;
    i++;
    k++;
  }
  else
  {
    k = next[k];
  }
  }
}
int KMP(char* str, char* sub, int pos)
{
  assert(str != NULL && sub != NULL);
  int lenStr = strlen(str);
  int lenSub = strlen(sub);
  if (lenStr == 0 || lenSub == 0)
  return -1;
  if (pos < 0 || pos >= lenStr)
  return -1;
  int* next = (int*)malloc(sizeof(int) * lenSub);
  assert(next != NULL);
  GetNext(sub, next, lenSub);
  int i = pos;//遍历主串
  int j = 0;//遍历子串
  while (i < lenStr && j < lenSub)
  {
  if (j == -1 || str[i] == sub[j])
  {
    i++;
    j++;
  }
  else
  {
    j = next[j];
  }
  }
  if (j >= lenSub)
  {
  return i - j;
  }
  return -1;
}
int main()
{
  printf("%d\n", KMP("ababcabcdabcde", "abcd", 0));
  printf("%d\n", KMP("ababcabcdabcde", "abcdf", 0));
  printf("%d\n", KMP("ababcabcdabcde", "ab", 0));
  return 0;
}


nextval数组改进

下面来看nextval数组的求解规则。


1.无论是什么数据,nextval[0]=-1;(这里还是默认数组的习惯从0开始计数)。如果是从1开始计数,则nextval[0]=0;。

2.从第二位开始,我们用next[i]值对应的字符与i值对应的字符进行比较。如果相等,则nextval[i]就等于next[i]值对应字符的nextval[i]值;如果不相等,则nextval[i]值就等于当前字符对应的next值。


我们还是来进行举例:


求模式串"a b c a a b b c a b c a a b d a b"。

7.png

下面来看详细过程:

第一个字符a对应的nextval[0]一定为-1(按照从0开始计数的话)。即nextval[0]=-1;

第二个字符b的next值即next[1]=0;所以第二个字符和下标为0的字符进行比较。发现不相等,所以nextval[1]=第二个字符所对应的next值,即nextval[1]=0;。

第三个字符c的next值即next[2]=0;所以第三个字符和下标为0的字符进行比较。发现不相等,所以nextval[2]=第三个字符所对应的next值,即nextval[2]=0;。

第四个字符a的next值即next[3]=0;所以第四个字符和下标为0的字符进行比较。发现相等了,所以nextval[3]=下标为0的字符所对应的nextval值,在这里就是nextval[3]=nextval[0]。

第五个字符a的next值即next[4]=1;所以第五个字符a和下标为1的字符b进行比较。发现不相等,所以nextval[4]=当前字符(即指的是第五个字符)所对应的next值,所以最终nextval[4]=next[4]=1。

依此类推进行分析,所以最终该串的nextval数组就如上图所示。


好了,以上就是关于字符串BF和KMP算法的一个记录。

就到这里吧,各位,再见啦!!!

目录
相关文章
|
6天前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
4天前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
1月前
|
自然语言处理 算法 搜索推荐
字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。
205 1
|
1月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
16天前
|
算法 C++
惊爆!KPM算法背后的秘密武器:一行代码揭秘字符串最小周期的终极奥义,让你秒变编程界周期大师!
【8月更文挑战第4天】字符串最小周期问题旨在找出字符串中最短重复子串的长度。KPM(实为KMP,Knuth-Morris-Pratt)算法,虽主要用于字符串匹配,但其生成的前缀函数(next数组)也可用于求解最小周期。核心思想是构建LPS数组,记录模式串中每个位置的最长相等前后缀长度。对于长度为n的字符串S,其最小周期T可通过公式ans = n - LPS[n-1]求得。通过分析周期字符串的特性,可证明该方法的有效性。提供的C++示例代码展示了如何计算给定字符串的最小周期,体现了KPM算法在解决此类问题上的高效性。
26 0
|
1月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
6天前
|
算法
基于模糊控制算法的倒立摆控制系统matlab仿真
本项目构建了一个基于模糊控制算法的倒立摆控制系统,利用MATLAB 2022a实现了从不稳定到稳定状态的转变,并输出了相应的动画和收敛过程。模糊控制器通过对小车位置与摆的角度误差及其变化量进行模糊化处理,依据预设的模糊规则库进行模糊推理并最终去模糊化为精确的控制量,成功地使倒立摆维持在直立位置。该方法无需精确数学模型,适用于处理系统的非线性和不确定性。
基于模糊控制算法的倒立摆控制系统matlab仿真
|
1天前
|
算法 数据安全/隐私保护
基于LS算法的OFDM+QPSK系统信道估计均衡matlab性能仿真
基于MATLAB 2022a的仿真展示了OFDM+QPSK系统中最小二乘(LS)算法的信道估计与均衡效果。OFDM利用多个低速率子载波提高频谱效率,通过循环前缀克服多径衰落。LS算法依据导频符号估计信道参数,进而设计均衡器以恢复数据符号。核心程序实现了OFDM信号处理流程,包括加性高斯白噪声的加入、保护间隔去除、快速傅立叶变换及信道估计与均衡等步骤,并最终计算误码率,验证了算法的有效性。
8 2
|
1天前
|
算法
基于GA-PSO遗传粒子群混合优化算法的CVRP问题求解matlab仿真
本文介绍了一种基于GA-PSO混合优化算法求解带容量限制的车辆路径问题(CVRP)的方法。在MATLAB2022a环境下运行,通过遗传算法的全局搜索与粒子群算法的局部优化能力互补,高效寻找最优解。程序采用自然数编码策略,通过选择、交叉、变异操作及粒子速度和位置更新,不断迭代直至满足终止条件,旨在最小化总行驶距离的同时满足客户需求和车辆载重限制。
|
5天前
|
机器学习/深度学习 算法 定位技术
MATLAB - 遗传算法(GA)求解旅行商问题(TSP)
MATLAB - 遗传算法(GA)求解旅行商问题(TSP)
12 3

热门文章

最新文章