KMP算法,BF算法
串、BF算法、KMP算法
概述
需要掌握:
1、串的相关概念,串与线性表之间的异同
2、顺序串,和链串中串的基本的基本运算算法设计
3、模式匹配算法BF、和KMP算法
串的相关概念,串与线性表之间的异同
str = "A(0)A(1)...A(n-1)"
1、n 是串的长度
2、n = 0时为"空串"
3、str = " "这样的由一个或多个的空格组成的为"空白串"
4、一个串当中的任意连续字符组成的子序列为"子串",包含所有字串的串就是"主串"
举例:
str = "123456.....n" 它的子串有多少?
答:空串"1",每一个字符也是一个子串"n",每两个连续字符也是一个子串"n-1"没三个连续的字符也是一个子串"n-2"....str本身也是一个子串
子串 = 1+n+(n-1)+(n-2).....2+1 = n(n+1)/2+1
注意:
学习子串有利于学习后面的算法
串的存储结构:
1、串的顺序存储结构————顺序串
这个串存储在一组连续的存储单元(数组就是分配了一块存储单元)
2、串的链式存储结构————链串
将串存储在多个存储单元里,但是每个存储单元是有联系的(链表)
线性表:
顺序存储结构
链式存储结构
注意:
这个顺序存储结构和线性存储结构是计算机对他们的内存分配而言,对我们的使用而言,串就是一个完整的串
模式匹配算法BF、和KMP算法
问题描述:
已有两个串s、t,在串s里找与t对应的子串,通常把s称为目标串,t为模式串。在目标串里找到模式串,存在该模式串返回true,不存在返回false
解决办法:
1、BF算法(暴力算法)
2、KMP算法
特别提醒:
我们只是利用者,这些算法都是牛人想到的,我们只是理解加记忆,不用纠结与为什么我们想不到,我也焦虑与他们为啥这么牛
接下来讲解我对他们的理解与实现
BF算法
解题思路:
1、取出模式串的第一个字符,与目标串的第一个进行比对
a.比对成功
取出模式串的下一个字符,与目标串的下一个比对(然后又是a,b)
b.比对不成功
将目标串回溯到第二个字符,模式串回溯到第一个字符
也就说目标串从索引为"0"开始,看后面的字符串是否与模式串匹配,不匹配,目标串就从索引为"1"开始,看后面的是否匹配...然后3.4.5....直到目标串遍历完
2、结束条件
c.当把目标串走完,也没有找到与模式串匹配的,返回false(也就是目标串遍历完)
d.当找到目标串返回true(也就是模式串全部走完)
注意:
如果没有理解,建议去找下图片呈现详细过程
public class ViolenceMatch {
public static boolean violenceMatch(String str1, String str2) {
char[] s = str1.toCharArray();// 目标串
char[] t = str2.toCharArray();// 模式串
int index = 0;//记录模式串匹配到的位置
for(int i = 0;i < s.length;i++) {
//如果匹配成功
if(s[i] == t[index]) {
index++;
//当把最后一个字符串也匹配成功了
if(index == t.length) {
return true;
}
else
continue;
}
//如果没成功,就回溯
if(s[i] != t[index]) {
index = 0;
i = i-index; //难点在这儿
continue;
}
}
return false;
}
//分析i = i - index 的由来,(这就是上面的 b )
a a a a b 目标串 a a b 模式串
第一趟:
a a a a b (i = 2)
a a b (index = 2)
这时候目标串需要从索引为 1 开始(i - index)+1 = 2-2+1
第二趟:
a a a a b (i = 3)
a a b (index = 2)
这时候目标串需要从索引为 2 开始,(i - index)+1 = 3-2+1
第三趟:
a a a a b
a a b
本来我想写一个flag记录目标串需要从哪里开始匹配,但是写半天没写出来(可能愚笨把,哭泣!)
kmp算法
解题思路:
1、假设计算机在依次比对目标串和模式串的时候,能够记住已经匹配的字符是什么
2、目标串t = "abbcabab",模式串s = "af" ,把他们转换成字符数组
我们比较t[0] == s[0], t[1] != t[1]这时候不相等,如果按照BF算法将比较t[1] 与 s[0]
但是我们假设计算机记住了已经比较的字符,那我们知道t[1] != a;那我们就直接这样比较了t[2] == s[0],这样是不是就不用回溯那么多了;
3、目标串t = "abcabcd",模式串s = "abcabf" ,把他们转换成字符数组
我们比较t[0] == s[0],t[1] == s[1],t[2] == s[2],t[3] == s[3],t[4] == s[4],t[5] != t[5]
如果是暴力解法的话,将比较t[1] != s[0],t[2] != s[0],t[3] == s[0],....他要比较很多次才比较到这里来
但是我么假设计算机记住了我们已经比较的字符,那我们知道t[0]t[1] == t[3]t[4] == ab == s[0]s[1] == s[3]s[4]
那我们就直接比较s[2]后面的字符和t[4]后面的字符
建议上述过程画图比较(就是说BF一个一个的移动,KMP是跳着移动)
4、那我们如何使计算机像人一样能够记住和识别呢??"公共前缀表"推荐好文 https://www.cnblogs.com/zzuuoo666/p/9028287.html
5、这里很抱歉,我感觉我讲的不是明白,但是应该还是有助于大家理解的
1 public int[] getPrifix(String str) {
2 //转换成字符数组方便操作
3 char[] charArray = str.toCharArray();
4
5 //定义一个数组接收str字符串的公共前后缀长度
6 int[] prifix = new int[charArray.length];
7
8 //prifixLength 接收字符串公共前后缀长度
9 int prifixLength = 0;
10
11 //遍历charArray
12 for(int q = 0;q < charArray.length;q++) {
13 //p 记录后缀的头指针,起始位置
14 int p = 1;
15 //i 前缀的头指针,j 后缀的头指针
16 for(int i = 0, j = 1;j <= q;) {
17 if(charArray[i] == charArray[j]) {
18 i++;
19 j++;
20 prifixLength++;
21 continue;
22 }
23 if(charArray[i] != charArray[j]) {
24 i = 0;
25 j = p+1;//回溯后缀指针到记录的下一个位置
26 p = j;//记录后缀的头指针,起始位置
27 prifixLength = 0;
28 continue;
29 }
30 }
31 prifix[q] = prifixLength;
32 prifixLength = 0;
33 }
34 return prifix;
35 }
/**
* @param str1 目标串
* @param str2 模式串
* @return true: 目标串存在与模式串相等的子串,false 目标串不存在与模式串相等的子串
*/
public static boolean KMP(String str1, String str2) {
// 转换模式串,目标串为字符数组,方便操作
char[] s = str1.toCharArray();
char[] t = str2.toCharArray();
int[] prifix = kmp.getPrifix(str2);
// 定义两个指针
int s_index = 0;
int t_index = 0;
while (true) {
if (s_index >= s.length || t_index >= t.length) {
return t_index >= t.length ? true : false;
}
if (s[s_index] == t[t_index]) {
s_index++;
t_index++;
continue;
}
if (s[s_index] != t[t_index] && t_index != 0) {
t_index = prifix[t_index - 1];
continue;
}
if (s[s_index] != t[t_index] && t_index == 0) {
// 为什么是它++呢,因为t_index == 0,这时候s[s_index+1] == t[t_index],也就是说目标串后移一位
s_index++;
continue;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】