【详解】KMP算法——多图,多例子(c语言)

这篇具有很好参考价值的文章主要介绍了【详解】KMP算法——多图,多例子(c语言)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

1.KMP算法是什么?

2.为什么需要KMP算法?

2.1主串找字串

2.2暴力求解

3.KMP准备工作

3.1字符串的前后子串

3.2最大前后相等子串

3.3最大前后相等子串练习

4.KMP算法

4.1简看KMP算法

5 Next数组     

5.1j该回溯的位置

 5.2学会计算Next数组           

5.3用数学表示next数组(重点)

5.3.1arr2[k] == arr2[j]

5.3.2 arr2[k] != arr2[j]

5.3.3 k回溯到尽头

6.代码实现KMP

6.1KMP外壳

6.2KMP内核

6.3KMP全部代码

7.结语


前言

KMP算法作为程序员的必修课之一,其抽象的过程让初学者叫苦不迭,但是当你完全理解过后会发现其中蕴含着创造者的无穷智慧。本篇文章我将以大量的例子与图片,为你讲解这个奇妙的算法。


1.KMP算法是什么?

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) [1]



 。(来自百度百科)

简而言之就是:减少在主串找子串的过程中回退的次数。(先有个概念就行,后面会仔细讲解)


2.为什么需要KMP算法?

在回答这个问题前我们需要知道先知道两个问题。

什么叫主串找子串?

不用kmp算法,直接暴力求解是怎样的?

2.1主串找字串

现在我们有主串:arr1[] = "abababc",子串:arr2[] = “abc”。那么我们在arr1中找到arr2在其中位置的过程就叫做主串找子串。

2.2暴力求解

在暴力求解中,我们是将子串和主串逐一匹配,如果第一个字符相等就继续匹配第二个字符,直到子串与主串全都匹配成功,就返回子串的位置,一旦其中某两个字符匹配不成功,主串就回到开始匹配字符的下一字符,而子串回到第一字符。

上面的话可能有一点绕,那么看了下面的图片你就会明白暴力求解的思路。

还是这俩字符串,主串:arr1[] = "abababc",子串:arr2[] = “abc”

(1) 第一次匹配成功,第二次匹配成功,第三次匹配不成功。

              【详解】KMP算法——多图,多例子(c语言)

 (2) 前面匹配失败,第一个字符串回到第二个字符'b',第二个字符串回到第一个字符'a'处。

           第一次匹配失败。

           【详解】KMP算法——多图,多例子(c语言)

(3) 前面匹配失败,第一个字符串回到第三个字符'a',第二个字符串回到第一个字符'a'处。

          第一次匹配成功,第二次匹配成功,第三次匹配不成功。

             【详解】KMP算法——多图,多例子(c语言)

(4) 前面匹配失败,第一个字符串回到第四个字符'b',第二个字符串回到第一个字符'a'处。

          第一次匹配失败。

               【详解】KMP算法——多图,多例子(c语言)

(5) 前面匹配失败,第一个字符串回到第五个字符'a',第二个字符串回到第一个字符'a'处。

          第一次匹配成功,第二次匹配成功,第三次匹配成功,子串走到尽头,成功找到在第一字符            串找到第二字符串。

                  【详解】KMP算法——多图,多例子(c语言)

通过以上举例可以看出,传统的暴力求解,需要多次回溯,且第一个字符串和第二个字符串都需要回溯,而且例如(2)(4)步,明显回溯过去也一定是错的,那有没有什么办法让他回溯到特定的位置,不至于像暴力求解一样,产生许多不必要的步骤,于是就有了本篇的重点:

                                                               KMP算法!!!


3.KMP准备工作

在学习KMP算法之前我们还需要进行一些小小的的准备。这对你掌握KMP算法是非常必要的

3.1字符串的前后子串

先抛开找字符串的问题,抛开什么KMP算法,我们来了解一下什么叫一个字符串的前后相等子串。

--假设有这样一个字符串:a[] = "abcabcabc";

那么他的前子串的集合为:{"a","ab","abc","abca","abcab","abcabc","abcabca","abcabcab"}

看不懂?上图!图片顺序是从左向右哦!(注:作者懒,字符串的\0我没画😉)

【详解】KMP算法——多图,多例子(c语言)

--知道了什么叫前子串,那么字符的后子串也很好理解了。

他的后子串的集合为:{"c","bc","abc","cabc","bcabc","abcabc","cabcabc","bcabcabc"}

【详解】KMP算法——多图,多例子(c语言)

3.2最大前后相等子串

我们现在已经知道了字符串a[] = "abcabcabc"的两个信息:

前子串的集合为:{"a","ab","abc","abca","abcab","abcabc","abcabca","abcabcab"}

后子串的集合为:{"c","bc","abc","cabc","bcabc","abcabc","cabcabc","bcabcabc"}

很明显就可以看出前后两个子串相等的有{"abc","abcabc"};

那最大前后相等子串就是"abcabc",其长度为6。

3.3最大前后相等子串练习

kmp算法的准备工作已经完成,如果你还是有点不太清楚,这里有几个字符串,你不妨可以试着找出他们的最大前后相等子串,以及长度,来加深你对前面内容的的理解。

        a[] = "abcdefgh"                         b[] = "abcabcabcabcabc"        c[] = "aba"

        d[] = "hello world"                       e[] = "ababcabcdabcde"          f[] = "abcabcdeabcabcde"

 答案:

a[]:没有最大前后相等子串    0
b[]:"abcabcabcabc"         12
c[]:"a"                    1
d[]:没有最大前后相等子串    0
e[]:没有最大前后相等子串    0
f[]:"abcabcde"             8

4.KMP算法

4.1简看KMP算法

前面我们多次强调过,kmp算法只需要子串返回到特定位置,而主串不用返回。

这到底是一个怎样的过程呢?

还是这俩字符串,主串:arr1[] = "abababc",子串:arr2[] = “abc”

绿色是回溯的位置红色是匹配结束的位置。

(1)第一次匹配成功,第二次匹配成功,第三次匹配失败。【详解】KMP算法——多图,多例子(c语言)

(2)前面不匹配失败,主串不回溯子串回溯到第一个字符,并与上次与主串匹配错误的位置匹配

         第一次匹配成功,第二次匹配成功,第三次匹配失败。【详解】KMP算法——多图,多例子(c语言)

(3)前面不匹配失败,主串不回溯子串回溯到第一个字符,并与上次与主串匹配错误的位置匹配

         第一次匹配成功,第二次匹配成功,第三次匹配成功。 【详解】KMP算法——多图,多例子(c语言)

 看样子KMP算法好像就是主串不回溯,子串回溯到初始位置而已嘛,感觉并没有说的那么强大啊。

那你可太小看KMP算法了,我们再来看一个例子:

主串:arr1[] = "abcababcabc",子串:arr2[] = “abcabc”

 (1)

【详解】KMP算法——多图,多例子(c语言)

 (2)

【详解】KMP算法——多图,多例子(c语言)

 (3)

【详解】KMP算法——多图,多例子(c语言)

 可以很明显的看到第二次匹配中,j并没有回溯到字符串的首位置而是回溯到字符串的第三个位置

这就是我们所说的j会回溯到一个特定位置的意思。


5 Next数组     

5.1j该回溯的位置

主串:arr1[] = "abcababcabc",子串:arr2[] = “abcabc”

【详解】KMP算法——多图,多例子(c语言)

 此时主串与子串在就 j = 5位置匹配失败,各位可以一一尝试,我们最好的结果就是回退到 j = 2处,因为主串和子串匹配失败一定有绿色的三个部分相等,而最大前后相等子串长度就是2即j返回位置。

【详解】KMP算法——多图,多例子(c语言)

 很明显就能看出根据最大前后相等子串的一些关系,能很轻松的将一些不必要的匹配略过,只从重要位置匹配,并且不用怕匹配遗漏的问题。

 5.2学会计算Next数组           

事实上,一个j会回溯的特定位置全都存放在一个Next[j] = k,数组中。

Next[j] = k :一个用来存放子串返回位置的数组,回溯的位置用字母k来表示。Next只与主串和子串匹配错误的位置,以及子串本身有关,与主串没有太大关系,所以后面我们将抛弃主串,只讲子串。

那回溯位置k是怎么求的呢?

1.从匹配失败位置,找到他前面的字符串的最大前后相等子串长度。

2.默认第一个k值为-1(Next[0] = -1),第二个k值为0(Next[1] = 0),我们只需要从第三个k值(Next[2])开始求。(这里不同的书籍或人规定的默认值有所不同

知道了Next数组的规则,我们开始求他了,假设我们有这样一个子串

arr2[11] = "abcababcabc"

Next []   ={  -1, 0 , ? , ? , ? , ? , ....... } 

【详解】KMP算法——多图,多例子(c语言)

(1)假设我们此时的子串与主串在 j = 2 时匹配失败

绿色代表需要找最大前后相等子串长度的字符串,橙色数字代表该字符串的最大前后相等子串长度

【详解】KMP算法——多图,多例子(c语言)

 (2)假设我们此时的子串与主串在 j = 3 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(3)假设我们此时的子串与主串在 j = 4 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(4)假设我们此时的子串与主串在 j = 5 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(5)假设我们此时的子串与主串在 j = 6 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(6)假设我们此时的子串与主串在 j = 7 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(7)假设我们此时的子串与主串在 j = 8 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(8)假设我们此时的子串与主串在 j = 9 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

(9)假设我们此时的子串与主串在 j = 10 时匹配失败

【详解】KMP算法——多图,多例子(c语言)

到此我们有:Next[i] = { -1 , 0 , 0 , 0 , 1 , 2 , 1 , 2 , 3 , 4 , 5 }

根据这样的规则,我们就得到了一个包含子串每一位错误时对应的退回位置k的数组,这个数组叫做Next,而且能知道,next数组的长度与子串的长度相同。

--Next数组计算练习

1.a[] = "ababcabcdabcde"

2.b[] = "abcabcabcabcdabcde"

答案:

a[]:   a b a b c a b c d a b c d e
      -1 0 0 1 2 0 1 2 0 0 1 2 0 0

b[]:   a b c a b c a b c a b c d a b c d e
      -1 0 0 0 1 2 3 4 5 6 7 8 9 0 1 2 3 0

5.3用数学表示next数组(重点)

通过前面的学习,你应该已经知道怎么求Next数组了,但那是你用眼睛去看出来的Next数组而不是用推导出来的Next数组,当计算机拿到一个子串,除了默认值设定的Next[0] = -1,Next[1] = 0,其他什么都不知道,Next数组后面的每一位都需要我们去设计计算出来。

5.3.1arr2[k] == arr2[j]

arr2[] = "abcababcabc"

假设我们已知Next = { -1 , 0 , 0 , 0 , 1 , 2 , 1 , 2 , 3 ,? },需要求解Next[9] = ?。

【详解】KMP算法——多图,多例子(c语言)

 此时令j = 8那已知信息就有 arr[j] = 'a'Next[j] = k = 3arr[k] = 'a',此时arr[j] = arr[k]

【详解】KMP算法——多图,多例子(c语言)那么:                                                                                                                                                  { arr2[ 0 ] , ... , arr2[ k - 1 ] } = "abc"  -->  { arr2[ x ] , ... , arr2[  j - 1 ] } = "abc"   即Next [ j ] = k = 3的原因

根据两组下标可知:(k-1) - 0 = (j - 1) - x  ,所以 x = j - k 。

将x带回到第二组的下标中:                                                                                                                 { arr2[   0   ] , ... , arr2[ k - 1 ] } = "abc"  --> { arr2[ j - x ] , ... , arr2[  j - 1 ] } = "abc"   

【详解】KMP算法——多图,多例子(c语言)

 又因为arr[j] = arr[k] :                                                                                                                        { arr2[   0   ] , ... , arr2[ k - 1 ] , arr2 [ k ] } = "abca"  -->  { arr2[ j - x ] , ... , arr2[  j - 1 ] , arr2 [ j  ] } = "abca" 

所以可知:Next [ j + 1 ]    =    k + 1   =    4  !!!!!!!!!!!!!!

注意1:一定要记住k就是最大前后相等子串长度。

【详解】KMP算法——多图,多例子(c语言)

结论1:arr2[k] == arr2[j] ⇒ Next [ j+1 ] = k + 1

5.3.2 arr2[k] != arr2[j]

前面我们已经知道了当arr2[k] == arr2[j],怎么求Next[ j + 1 ] ,现在我们再来看看当               arr2[k] != arr2[j]的情况

arr2[] = "abcababcabc"

假设我们已知Next = { -1 , 0 , 0 , 0 , 1 , 2 , ? },需要求解Next[6] = ?。

【详解】KMP算法——多图,多例子(c语言)

 此时令j = 5那已知信息就有 arr[j] = 'a'Next[j] = k = 2arr[k] = 'c',此时arr[j] != arr[k]

【详解】KMP算法——多图,多例子(c语言)

 那我们就让新的 k = Next[ k ] = 0。【详解】KMP算法——多图,多例子(c语言)

 此时我们又有已知信息 arr[j] = 'a'Next[j] = k = 2arr[k] = 'a',arr[j] = arr[k]

一些细心的读者可能会发现,现在又成了前一种情况arr[j] == arr[k]。

因此我们要求解的 Next[ j + 1 ] 根据之前推导的公式Next[ j + 1] = k + 1  Next [ j + 1 ] = 1。 

注意2:此时的 k 已经被改变过了,是新的k

结论2:arr2[k] != arr2[j] ⇒ Next[ j+1 ] =  k  +  1 

5.3.3 k回溯到尽头

一些读者可能又会提出疑问:我的例子太特殊,要是k一直往Next数组前面走,走到第一个元素都找不到相等呢?

一直都找不到,那我们此时k肯定回溯到了数组头部,即k = - 1处,那我们就停止回溯,             Next [ j + 1 ] = k + 1  Next [ j + 1] = 0。

结论3:k == -1 ⇒ Next[ j+1 ] = k + 1 。即Next[ j + 1 ] = 0。

以上就是KMP的精华所在,创造者成功的找到了高效回溯的之中存在的潜藏规律。这下你们大概能理解为什么KMP算法如此令人着迷了吧。


6.代码实现KMP

至此,如果你将前面的内容都理解了,那你基本把KMP算法掌握的差不多了,只剩如何用代码写出来的问题。下面我会分为两个部分讲解,有一定基础的读者也可以先尝试自己写一写,等遇到问题再回来看看我的代码与你的有何区别

6.1KMP外壳

现在我们不去管如何用代码得到Next数组,而是将Next数组当作已知,尝试通过写出KMP算法的外壳。

这里有三个要点:

1.主串不回退

2.子串回退到一个特殊的位置(通过前面我们已经知道,回退的特殊位置就是Next[ j ] = k

3.假设Next数组已知

代码如下:

#include<stdio.h>
#include<string.h>
int KMP(char* arr1, char* arr2)
{
	int i = 0;											//不需要记录匹配的首位置,
	int j = 0;                                          //因为kmp算法i不需要回溯
	
	int len1 = strlen(arr1);
	int len2 = strlen(arr2);
	
	int Next[len2] = {0};                               //假设Next已经得到,其长度为子
                                                        //串的长度
	
	if (len1 == 0 && len2 == 0 || len2 == 0)            //当arr1与arr2都为空或arr1为空
        return 0;                                       //时直接返回
	
    else if (len1 == 0 || len2 > len1) 		            //当arr1为空或者第二个字符串比
        return -1;                                      //第一个字符串长,不可能找到
	
	while (i < len1 && j < len2)						//当arr1和arr2都没走到尽头
	{
		if (arr1[i] == arr2[j])
		{
			i++;
			j++;
		}
		else
		{
			j = Next[j];						        //当主串与子串不同时j回溯到 
                                                        //Next[j],i不用回溯
		}
	}
	if (j >= len2)
		return i - j;							        //如果子串走到尽头,代表找到了 
                                                        //返回开始匹配时的位置
	
    return -1;											//否则就是主串走到尽头,代表没
                                                        //找到
}

6.2KMP内核

前面的代码相信大部分人都能够轻松完成,就是简单的对暴力求解进行了一点改造而已,那接下来我们去用代码求得Next数组。

这里我们只需要借助我们前面推出来的三个结论:

结论1:arr2[k] == arr2[j] ⇒ Next[ j+1 ] = k + 1        k不往子串前走

结论2:arr2[k] != arr2[j] ⇒ Next[ j+1 ] =  k  +  1      k往子串前走

结论3:k == -1                ⇒  Next[ j+1 ] = k + 1        k走到子串尽头

注意:虽然三个结论看起来相似,但一定要记住每个k分别是什么意思

代码如下:

void GetNext(int* Next, const char* arr2)           //传入Next数组地址,传入子串首地址
{
	int j = 1;										//初始已知项 j = 1
	int i = j + 1;									//初始待求项 j+1 = 2
	int k = 0;                                      //待求的Next[j+1]前一项的k值
	
	int len2 = strlen(arr2);                        //子串长度
	
	Next[0] = -1;									//Next数组前两个默认值
	Next[1] = 0;
	
	while (i < len2)                                //当待求项走到arr2尽头,k全求出
	{
		if ((k == -1) || arr2[k] == arr2[i - 1])	//结论1,结论3情况
		{
			Next[i] = k + 1;
			k = k + 1;                              //待求的Next[j+1]前一项的k值
			i++;                                    //待求项往后走一位
		}
		else
		{
			k = Next[k];							//结论2情况
		}
	}
}

6.3KMP全部代码

前面的代码很明显只将两个部分单独写出,并没有做出联系,因此还需要一些改动。

#include<stdio.h>
#include<string.h>

void GetNext(int* Next, const char* arr2)           //传入Next数组地址,传入子串首地址
{
	int j = 1;										//初始已知项 j = 1
	int i = j + 1;									//初始待求项 j+1 = 2
	int k = 0;                                      //待求的Next[j+1]前一项的k值
	
	int len2 = strlen(arr2);                        //子串长度
	
	Next[0] = -1;									//Next数组前两个默认值
	Next[1] = 0;
	
	while (i < len2)                                //当待求项走到arr2尽头,找完Next数组
	{
		if ((k == -1) || arr2[k] == arr2[i - 1])	//结论1,结论3情况
		{
			Next[i] = k + 1;
			k = k + 1;                              //待求的Next[j+1]前一项的k值
			i++;                                    //待求项往后走一位
		}
		else
		{
			k = Next[k];							//结论2情况
		}
	}
}

int KMP(char* arr1, char* arr2)
{
	int i = 0;											//不需要记录匹配的首位置,
	int j = 0;                                          //因为kmp算法i不需要回溯
	
	int len1 = strlen(arr1);
	int len2 = strlen(arr2);
	
	int* Next = (int*)malloc(len2 * sizeof(int));       //为Next数组开辟一个与子串一样长的 
                                                        //空间
	
	GetNext(Next, arr2);                                //借用Next函数得到Next数组的内容

	if (len1 == 0 && len2 == 0 || len2 == 0) return 0;	//当arr1与arr2都为空或arr1为空时直 
                                                        //接返回

	else if (len1 == 0 || len2 > len1) return -1;		//当arr1为空或者第二个字符串比第一 
                                                        //个字符串长
	
	while (i < len1 && j < len2)						//当arr1和arr2都没走到尽头
	{
		if (arr1[i] == arr2[j])
		{
			i++;
			j++;
		}
		else
		{
			j = Next[j];						        //当主串与子串不同时j回溯到 
                                                        //Next[j],i不用回溯
		}
	}
	if (j >= len2)
		return i - j;							        //如果子串走到尽头,代表找到了返回 
                                                        //开始匹配时的位置
	return -1;											//否则就是主串走到尽头,代表没找到
}

int main()
{
	char arr1[] = "abababcabc";         //测试用             
	char arr2[] = "abcabc";
	char pos;
	pos = KMP(arr1, arr2);
	printf("%d", pos);
}

7.结语

写下这篇博客,不单单是教大家,同时也是我自己的一个学习总结,如果各位学到了东西,还请不要吝惜你们的点赞收藏,这也将激励我写出更好的文章。

特别鸣谢:

@比特大博哥,如果大家看了我的视频还是有所不懂可以看大博哥的视频b站:BV1UL411E7M8文章来源地址https://www.toymoban.com/news/detail-422135.html

到了这里,关于【详解】KMP算法——多图,多例子(c语言)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [数据结构] 串与KMP算法详解

    今天是农历大年初三,祝大家新年快乐! 尽管新旧交替只是一个瞬间,在大家互祝新年快乐的瞬间,在时钟倒计时数到零的瞬间,在烟花在黑色幕布绽放的瞬间,在心底默默许下愿望的瞬间……跨入新的一年,并不意味了一切都会朝着更美好,也没有什么会从天而降,我们赋

    2024年02月19日
    浏览(31)
  • KMP算法细节详解(带动图理解)

    KMP算法是为了字符串匹配问题而被研究出来的,字符串匹配问题就是查看一个字符串A是否是字符串B的子串,如果是字串的话,在B的哪个位置?此算法代码简练,但理解起来非常困难,建议挑出一整块时间来专门学习,本文作者写的非常用心,还不了解KMP的小伙伴一定要静下

    2024年02月04日
    浏览(45)
  • (C语言)数据结构算法-病毒感染检测(BF算法&&KMP算法)

    病毒感染检测: 医学研究者最近发现了某些新病毒,得知它们的DNA序列都是环状的。为了快速检测出患者是否感染了相应的病毒,研究者将患者的DNA和病毒的DNA均表示成一些字母组成的字符串序列,然后检测某种病毒DNA序列是否在患者的DNA序列中出现过,如果出现过,则此人

    2024年02月08日
    浏览(38)
  • 【最短路算法】一篇文章彻底弄懂Dijkstra算法|多图解+代码详解

    博主简介: 努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:算法、数据结构、Java等相关知识。 博主主页: @是瑶瑶子啦 所属专栏: 算法 ;该专栏专注于蓝桥杯和ACM等算法竞赛🔥 近期目标: 写好专栏的每一篇文章 Dijkstra算法适用于 最短路问题

    2023年04月08日
    浏览(31)
  • 数据结构-串-KMP算法详解(Next数组计算)(简单易懂)

    本文章就专讲kmp,暴力匹配就不讲了(我相信能搜索kmp的,暴力匹配算法应该也都了解过了) 为什么网上那么多讲kmp 我还发文章,很多文章我觉得讲的不是太通俗易懂,大多数我看起来都觉得有些懵逼 提示:以下信息来源百度 KMP算法是一种改进的字符串匹配算法,由D.E.K

    2024年02月06日
    浏览(33)
  • (详细图解)KMP算法(C语言)------可算领悟了这个由三位前辈研究的算法

    目录   前言 一、简介KMP算法 二、朴素的模式匹配算法 第一种朴素的模式匹配算法的写法 第二种朴素的模式匹配算法的写法 一个例子 第三总结 三、KMP算法 1、字符串的前缀、后缀和部分匹配值 2、KMP算法的原理 算法改进 1、主串、子串从数组索引为 1 处开始存储字符 2、主

    2024年03月12日
    浏览(57)
  • 贪心算法及几个经典例子c语言

    一、基本概念: 所谓贪心算法是指,在对问题求解时,总是做出在 当前看来是最好的选择 。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的 局部最优解 。 贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不

    2024年02月01日
    浏览(25)
  • C语言数据结构+KMP算法next数组优化计算方法+优化后子串匹配代码实现

    通过我之前那篇KMP算法的讲解,我们可以快速手算KMP算法的next数组,但是之前计算的next数组在一些情况下会有缺陷,比如模式串’aaaab’和主串’aaabaaaab’进行匹配 令模式串指针为j 当第一个元素不匹配时,下一次匹配还是要从模式串的第一个元素与主串匹配,其实我们可以直接写

    2024年02月06日
    浏览(34)
  • 图解KMP算法,带你彻底吃透KMP

    KMP算法 一直是一个比较难以理解的算法,本篇文章主要根据《大话数据结构》中关于KMP算法的讲解,结合自己的思考,对于KMP算法进行一个比较详细的解释。 由于博主本人水平有限,难免会出现一些错误。如果发现文章中存在错误敬请批评指正,感谢您的阅读。 字符串模式

    2024年02月08日
    浏览(42)
  • 【算法思维】-- KMP算法

    OJ须知: 一般而言,OJ在1s内能接受的算法时间复杂度:10e8 ~ 10e9之间(中值5*10e8)。在竞赛中, 一般认为计算机1秒能执行 5*10e8 次计算 。 时间复杂度 取值范围 o(log2n) 大的离谱 O(n) 10e8 O(nlog(n)) 10e6 O(nsqrt(n))) 10e5 O(n^2) 5000 O(n^3) 300 O(2^n) 25 O(3^n) 15 O(n!) 11 时间复杂度排序: o(1)

    2024年02月06日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包