서문 :
어떻게 알고리즘 코드가 배운 것을 기억하지만, 문제를 어떻게 배운다.
알고리즘은 정말 티치 다른 사람에게 배울 수 있습니다.
예를 인용 두 문자열 S 및 T 감안 T Q S 서브 스트링에 속하는 경우.
이것은 기본 문자열 일치 문제, 우리는 쉽게 브 루트 포스 방법을 생각할 수 있습니다.
브 루트 포스 방법 :
설명의 편의와 이해를 위해, 우리는 패턴 문자열의 주요 문자열 문자열 S, T 문자열을 호출합니다.
문자 인 경우 시작하는 주요 캐릭터 열거 패턴 문자열에서 같은 경기를 뒤로 계속 다른 출발점 업데이트하고 경기를 다시 시작하는 것입니다.
포인터 I, J의 정의
내가 : i 번째 주요 문자열 일치 문자
J : 이전이 일치 한 문자열 패턴 J 문자
초기 상태
문자 스트링의 메인 일치한다 [I] = 'A'및 모드 문자열 동일 t [J + 1] = 'A', 일치 성공. 포인터 이동 후, ++; J ++.
마찬가지로, 다음 경기 후,
S 메인 캐릭터가 다음 문자 t [I] = 'B'모드와 문자열 매칭되도록 [J를 + 1] = 'A ' 다른은 일치하지. i가 2 = 시작점 업데이트 열거는 정합 렌 문자 수가 대응되는 문자열 J == (패턴 문자열 길이)까지 패턴까지 다시 시작된다.
기준 시간 복잡도 : O (N * m)
KMP 알고리즘 :
KMP 알고리즘의 특성상 무력 방법을 최적화. 삭제 작업은 재사용 가능한 정보, 유효하지 않습니다.
하자, 프로세스의 시뮬레이션 위에서 설명한 계속
점과 경기를 시작하기 몇 가지 업데이트 후, 우리는 더 많은 국가에 비해 얻을. 절차의 무단 동력 방법에 따라, 순간에 매치가 실패 난 = 5에 따라서 시작점 업데이트 열거부터 = 4.
그러나 실제로 이러한 작업을하지 않아도, 우리는 관찰 :
设K, 님의 [IK] S ... [I-2]의 [I-1] t = [1] ... T [K-1] T [K] ( S <IK <= I-1 )
K가 존재하지 않는다면, 어떤 점 D (들 <D <= I-1)의 시작 지점으로의 패턴의 문자열과 일치 할 수 없다. ①
K가 존재하는 경우 :
만약 t [K + 1]! = [I] S는, 이 패턴의 문자열과 일치 할 수 없다. ②
若t[k+1]=s[i],则有可能以i-k为起点匹配出模式串。
①:都会因s[i-1]或之前的某个字符失配而断掉。
②:会因s[i]失配而断掉。
图1:不存在满足条件的k,从任意起点p(s<p<=i-1)都因某字符q匹配不到i-1
图2:存在满足条件的k,但t[k+1]!=s[i],因字符i匹配不到i-1
图3:既存在满足条件的k,t[k+1]=s[i],那么则有可能以i-k为起点匹配出模式串
因而,当匹配失败时,只需找到满足条件的k的最大值。若存在,主串向后匹配,以i-k为起点;若不存在,主串也向后匹配,寻找新的起点。
请思考,选择最大的k是否会漏掉可能的匹配起点?(答案见下文)
算法实现:
我们知道:s[s]..s[i-2]s[i-1]=t[1]..t[j-1]t[j]
因为s<i-k<=i-1,
所以s[i-k]..s[i-2]s[i-1]=t[j-k+1]..t[j-1]t[j]
因而我们只需要在模式串已匹配部分寻找k即可。
由于通常情况下模式串长度比较小,我们可以初始化出模式串中每个位置的k值。我们常用next[]数组存储模式串中每个位置的k值。
那么如何求得next[i]?
其实我们求得next[i]的过程等价于用模式串匹配自身的过程。为位置i寻找最长前缀后缀,可以想成用i前面的字符串去匹配模式串,到i最多能够匹配多长。这样以来问题就迎刃而解了,我们只需要进行两次匹配,一次求得next数组,一次匹配模式串。
注意:满足条件的k是指由i-k到i-1能够匹配模式串前k个字符,同时s[i+1]=t[k+1]!
算法流程:
1.初始化指针i=1,j=0
2.循环枚举主串待匹配字符i
3.枚举一个字符就对模式串进行一次匹配:
若s[i]=t[j+1],则模式串第j+1个字符匹配成功,i++;j++
若s[i]!=t[j+1],匹配失败,则更新j等于最长的满足条件的k,i++
4.当j=len时,匹配成功,跳出循环。
代码如下:
1 void get_next() 2 { 3 int i,j; 4 j=0; 5 next[1]=0; 6 for(i=2;i<=lent;i++){ 7 while(j>0&&t[j+1]!=t[i])j=next[j]; 8 if(t[j+1]==t[i])j++; 9 next[i]=j; 10 } 11 } 12 13 void KMP() 14 { 15 int i,j; 16 j=0; 17 for(i=1;i<=lens;i++){ 18 while(j>0&&t[j+1]!=s[i])j=next[j]; 19 if(t[j+1]==s[i])j++; 20 if(j==lent)ans[++cnt]=i-j+1; 21 } 22 }
next数组的求得很关键,这几天要期末考试,学业繁重。日后加图完善!