KMP的next陣列求法詳解
近幾天學習kmp演算法,在next陣列求解上受苦頗深,看了不少部落格,感覺寫得都不夠清晰,所以想按照自己理解的過程來嘗試寫一下,也便於以後溫習。
關於kmp演算法的介紹,網上博文有很多,就不再贅述,推薦一篇kmp演算法,個人感覺挺好
這裡主要詳細講解next陣列的求解。
由於在下不擅作圖,有的地方單純用文字描述不夠清晰,還請原諒。
若有什麼地方寫得不對歡迎批評,以便於在下修正。
kmp演算法的精髓就在於next陣列,從而達到跳躍式匹配的高效模式。
而next陣列的值是代表著字串的字首與字尾相同的最大長度,(不能包括自身)。
這裡舉個例子:
模式串t A B A B A A
下標 0 1 2 3 4 5
next 0 0 1 2 3 1
next[0]代表t[0]~t[0]即"A"的最大前後綴,顯然為0.
next[1]代表t[0]~t[1]即"AB"的最大前後綴,為0.
next[2]代表t[0]~t[2]即"ABA"的最大前後綴,即"A",長度為1.
next[3]代表t[0]~t[3]即"ABAB"的最大前後綴,即"AB",長度為2.
next[4]代表t[0]~t[4]即"ABABA"的最大前後綴,即"ABA",長度為3.
next[5]代表t[0]~t[5]即"ABABAA"的最大前後綴,即"A",長度為1.
看到這裡,next值代表的意義應該可以明白了。
但next陣列怎樣用程式碼去求呢,我們當然不可能挨個去比較前後綴。
仍然是上面那個例子
A B A B A A
初始化,next[0]為0;
t[0] != t[1] next[1]為0;
t[0] == t[2] next[2]為1;
在求next[3]時,比較t[1]和t[3]是否相等?
相等:顯然 next[3] = next[2]+1;
不相等:怎麼辦? 看下面
void makeNext(char s[],int next[])
{
int len = strlen(s);
next[0]=0; //初始化
for(int i=1,k=0;i<len;i++)
{
while(k>0 && s[k]!=s[i]) //這個while是最關鍵的部分
k=next[k-1];
//等價於 k=next[next[i-1]-1]
//等號右邊的k起的只是下標的作用
if (s[k]==s[i])
k++; //相等就+1
next[i]=k; //賦值
}
}
例子說話
A B A B A B A C
0 1 2 3 4 5 6 7
next[6] = 5
即字首為t[0]~t[4] 字尾為t[2]~t[6]
next[4] = 3
即字首為t[0]~t[2] 字尾為t[2]~t[4]
我們發現
next[4]的字首一定是next[6]的字首
next[4]的字尾也一定是next[6]的字尾
(這是while迴圈的原理,可以試著舉個例子驗證一下)
現在我們要求next[7],將t[7]與t[5] ( t[next[6]] )比較,發現不相等
那麼可以將t[7]與t[3] (t[ next[next[6]-1] ])比較,如果相等,則next[7] = next[4] +1 ;
不相等就重複此過程,直到t[7]與t[0]比較.
上框內過程其實就是程式碼中,while迴圈裡的內容,現在回過頭去看上面程式碼應該會順暢很多。
下面附上kmp完整程式碼
/*************************************************************************
> File Name: kmp.cpp
> Author:
> Mail: [email protected]
> Created Time: 2015年10月12日 星期一 18時32分00秒
************************************************************************/
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
void makeNext(char s[],int next[])
{
int len = strlen(s);
next[0]=0;
for(int i=1,k=0;i<len;i++)
{
while(k>0 && s[k]!=s[i])
k=next[k-1];
if(s[k]==s[i])
k++;
next[i]=k;
}
}
int kmp(char t[],char s[])
{
int len1 = strlen(t);
int len2 = strlen(s);
int next[len2];
makeNext(s,next);
for(int i=0,j=0;i<len1;i++)
{
while(j>0 && t[i]!=s[j])
{
j=next[j-1];
}
if(t[i]==s[j])
j++;
if(j==len2)
return i-j+1;
}
}
int main()
{
char t[]="1234561123458412";
char s[]="611";
cout<<t<<endl;
cout<<s<<endl;
cout<<"下標為"<<kmp(t,s)<<endl;
}
相關推薦
KMP的next陣列求法詳解
近幾天學習kmp演算法,在next陣列求解上受苦頗深,看了不少部落格,感覺寫得都不夠清晰,所以想按照自己理解的過程來嘗試寫一下,也便於以後溫習。 關於kmp演算法的介紹,網上博文有很多,就不再贅述,推薦一篇kmp演算法,個人感覺挺好 這裡主要詳細講解next
liunx磁盤陣列raid詳解
liunx raid 一丶raid 1.raid定義 磁盤陣列(Redundant Arrays of Independent Disks,RAID),有“獨立磁盤構成的具有冗余能力的陣列”之意。磁盤陣列是由很多價格較便宜的磁盤,組合成一個容量巨大的磁盤組,利用個別磁盤提供數據所產生加成效果提升整個磁
JS中陣列方法詳解
JS中陣列的方法有很多,但是自己一直沒有抽時間進行整理分類,故單獨寫一篇博文,對目前我所掌握的JS中陣列相關的方法進行整理,夯實一下自己的基礎。 我將陣列相關的方法分為兩類 1.方法會改變原陣列 相應的方法有:shift、unshift、pop、push、rev
Javascript 陣列語法詳解
JavaScript 中的陣列相當於 Java 中的 Map ,陣列本身是一個物件,屬於引用資料型別 更多精彩 更多技術部落格,請移步 asing1elife’s blog 定義 既然陣列是一個物件,當進行 alert(arr) 時
Linux系統常用磁碟陣列RAID5詳解
RAID5最少由3塊硬碟組成,每個硬碟容量一樣,資料儲存於磁碟陣列中的每個硬碟,其中一塊硬碟儲存資料校驗位,當丟失其中的一位時,RAID5能通過演算法,利用其他兩位資料將丟失的資料進行計算還原,因此RAID5最多隻能允許一塊硬碟損壞,可見磁碟利用率是(N-1)/N,資料的安全性得以保障,一般大多數人選擇用RA
RAID-磁碟陣列簡單詳解
歷史來源 1988 年美國加州大學伯克利分校的 D. A. Patterson 教授等首次在論文 “A Case of Redundant Array of Inexpensive Disks” 中提出了 RAID 概念 ,即廉價冗餘磁碟陣列( Redunda
動態陣列vector詳解(Java和C++)
1.概念描述: vector名為動態陣列 有些時候想開一個數組,但是卻不知道應該開多大長度的數組合適,因為我們需要用到的陣列很可能會根據情況變動。這時候我們就需要用到動態陣列。所謂動態陣列,也就是不定
C99可變長陣列VLA詳解
C90及C++的陣列物件定義是靜態聯編的,在編譯期就必須給定物件的完整資訊。但在程式設計過程中,我們常常遇到需要根據上下文環境來定義陣列的情況,在執行期才能確知陣列的長度。對於這種情況,C90及C++沒有什麼很好的辦法去解決(STL的方法除外),只能在堆中建立一個記憶體映像與需求陣列一樣的替代品,這種替
指標與陣列概念、指標陣列、陣列指標詳解
指標與陣列 指標可以與變數結合,也可以與陣列結合使用。指標陣列和陣列指標是兩個截然不同的概念,指標陣列是一種陣列,該陣列存放的是一組變數的地址。陣列指標是一個指標,表示該指標是指向陣列的指標。 1.指向陣列元素的指標 int a[5]={1,2,3,4,5}; int *p=a; //
next陣列求解詳解
next陣列的求解方法是: 第一位的next值為0,第二位的next值為1,後面求解每一位的next值時,根據前一位進行比較。首先將前一位與其next值對應的內容進行比較,如果相等,則該位的next值就是前一位的next值加上1;如果不等,向前繼續尋找n
【原創】C++ 動態陣列 vector 詳解
一、引入 引入:略 vector收錄在STL裡,是一種特殊的資料結構。它的中文名字叫做“動態陣列”或者“不定長陣列”,有時也被翻譯成“容器”。 說白了,vector就是一個功能強大的陣列。下面讓我
Python中三維陣列位置詳解
圖示效果圖: 直接貼程式碼: def test3D(): import numpy as np data_array = np.zeros((3, 5, 6), dtype=np.int) &
"array"陣列容器 詳解
"array<>"陣列容器 詳解陣列容器, 是儲存陣列的容器, 是C型別陣列的擴充, 可以使用迭代器進行操作;例如"std::array<int, 5>", 需要注意的是, 如果
Leetcode 33 搜尋旋轉排序陣列 思路詳解+反思總結 python實現
本人一直在努力地積累Leetcode上用Python實現的題,並且會盡力講清每道題的原理,絕不像其他某些部落格簡略地帶過。如果覺得講的清楚,歡迎關注。題目:假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5
2016多校訓練#5 1012 HDU 5792 樹狀陣列 程式碼詳解
World is Exploding Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s
二維陣列的詳解 :
二維陣列在概念上是二維的,有行和列,但在記憶體中所有的陣列元素都是連續排列的,它們之間沒有“縫隙”。 要用陣列指標來操作二維陣列。int (*p)[4]=a; //p每移動一次就是移動了一個一維陣列。 指標陣列:int *p=a[4];
樹狀陣列總結——詳解(單點/區間查詢, 單點/區間修改, 逆序對)
2017-06-13 17:24 64人閱讀 評論(0)收藏舉報 1、概述 樹狀陣列(binary indexed tree),是一種設計新穎的陣列結構,它能夠高效地獲取陣列中連續n個數的和。概括說,樹狀陣列通常用於解決以下問題:陣列{a}中的元素可能不斷地被
磁碟陣列RAID詳解
一、功能 1 對磁碟高速存取(提速) 2 擴容 3 資料冗餘 二、分類 RAID可分為級別0到級別6,通常稱為:RAID0,RAID1,RAID2,RAID3,RAID4,RAID5,RAID6。 RAID0:RAID0並不是真正的RAID結構,沒有資料冗餘,RAID0連續地分割資料並並行地讀/寫
C 語言中二維陣列指標詳解
C語言中,指標是一個複雜但又靈活多變的知識點,我們知道,在一維陣列中,對於一個數組a[],*a,a,&a,都表示a的首地址,但如果與二維陣列混合使用,就顯得更為複雜了。例如對於一個二維陣列 a[2][4]={{1,2.3},{4,5,6}} a+i,&a
C++中陣列引數詳解
// 引數為10個int的陣列// parameter is a reference to an array of 10 intsvoid putValues(int (&arr)[10]);int main(){ int i, j[2]; int a[10]; putValue