KMPアルゴリズム一般的に使用されるアルゴリズム10プログラマー
この記事は、最初のプログラマは、一般的なアルゴリズムの後ろに、トップ10に使用されるアルゴリズムですがブログに要約されています!!!
A.シナリオ
文字列照合問題:
- そこ文字列STR1 =「である」シリコンバレーシリコンバレーには、まだあなたはまだシリコンバレーはまだあなたはまだあなたはまだシリコンバレーこんにちは「」、およびサブストリングSTR2 =「まだ、まだあなたシリコンバレーます。」
- それは今STR1 STR2を含むかどうかを決定するために、存在している場合ではない場合、それは、最初の発生の位置を返し、それは-1を返します
II。暴力マッチングアルゴリズム
アイデアの2.1分析
暴力マッチングの考えた場合、およびSTR1 STR2位置をサブストリングマッチした位置I、Jにマッチした今と仮定すると、あります。
- 現在の文字が成功(つまり、一致した場合str1の[i]を== str2の[Jを ])、 その後++ I、J ++は、次の文字にマッチし続け
- もしミスマッチ(すなわちSTR1 [I] = str2の[J ]!)、 だから私は、I = - (J - 1) 、J = 0。各マッチに対応する障害が、私はバックトラック場合、jを0に設定されています。
- 解決策は、暴力を使用することで、そこになりますバックトラックの多くは、一致しない場合、その後、次の裁判官に移動する多くの時間を無駄に、1を移動する時間。(不可!)
2.2コードの実装
package algorithm;
/**
* @author 陌生人
* @version V1.0
* @Title:
* @Package
* @Description: (用一句话描述该文件做什么)
* @date:
*/
public class ViolenceMatch {
public static void main(String[] args) {
String str1 = "硅硅谷 尚硅谷你尚硅 尚硅谷你尚硅谷你尚硅你好";
String str2 = "尚硅谷你尚硅";
int index = violenceMatch(str1, str2);
System.out.println("index=" + index);
}
public static int violenceMatch(String s1, String s2) {
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
int i = 0;
int j = 0;
int s1len = s1.length();
int s2len = s2.length();
while (i < s1len && j < s2len) {
if (c1[i] == c2[j]) {
i++;
j++;
} else {
i = i - j + 1;
j = 0;
}
}
if (j == s2len) {
return i - j;
} else {
return -1;
}
}
}
III。アルゴリズムを導入
- KMPが発生した場合、があったかどうかをテキスト文字列内の文字列を解決するためのモデル、最も初期の古典的アルゴリズムの場所です
- クヌース - モリス - プラット文字列検索アルゴリズム、多くの場合、Pは、テキスト文字列Sに表示されるパターン文字列の位置を見つけるために使用される、「KMPアルゴリズム」と3のドナルド・クヌース、ヴォーン・プラット、ジェームス・H・モリスのアルゴリズムを参照しそれは、アルゴリズムにちなんで名付けられた3人を選んだように、1977年に共同で発表しました。
- アルゴリズムは次のアレイ、パターン文字列の前及び後に記憶された最長共通サブシーケンスの長さを介して情報を介してKMPの方法を用いて決定される前に、アレイずつバックは、マッチング位置の前面上、次を見つけるために、計算の大規模な量を除去します時間
四.KMPアルゴリズムの最適なアプリケーション
4.1文字列のマッチング問題
文字列のマッチング問題:
- 文字列STR1 = "BBC ABCDAB ABCDABCDABDE"、およびサブストリングSTR2 = "ABCDABD"
- それは今STR1 STR2を含むかどうかを決定するために、存在している場合ではない場合、それは、最初の発生の位置を返し、それは-1を返します
- 要件:KMPアルゴリズムが完了判断を使用するには、単に暴力マッチングアルゴリズムを使用することはできません。
グラフィックアイデアの4.2分析
例えば、文字列STR1 = "BBC ABCDAB ABCDABCDABDEは"、別の文字列STR2 = "ABCDABD" が含まれ、決定されますか?
-
まず、STR1最初の文字と比較するSTR2の最初の文字、それはない、移動後方Aキーワード
-
繰り返しステップか、その後、移動バック
-
str1が最初の文字と文字がSTR2まで満たしている必要がありまで繰り返されます
-
そして、文字列と検索用語で、またはラインで次の文字を比較します。
-
STR1はSTR2の文字が一致していない対応する文字に遭遇しました。
-
この時点で、我々は次の文字STR1のステップ1を繰り返しを横断し続けることをことを期待しています。(実際には、BCDを比較しているので、反復作業、基本的な事実を行う必要はスペースとDが一致しないとき、あなたは実際には最初の6つの文字が「ABCDAB」を知っているということではありません、非常に賢明ではありません。 KMPアルゴリズムのアイデアが位置を比較したバック移動しないように「検索位置」に、この既知の情報を使用しようとすることです、それはこのように効率を向上させ、後方に移動し続けます。)
- どのように単に省略手順を繰り返していますか?STR2は「部分一致テーブル」を計算することができます
- Dは、スペースを知られており、最初の6つの文字「ABCDAB」一致と一致していません。ルックアップテーブルを見ることができる、「部分一致する値」に対応する最後の一致文字Bが2であるので、次式の後退により算出されたビットの数:
マッチした文字のシフトビット数=番号-マッチング値に対応する部分
6のように-図2は、検索語ムーブバック4ので、4に等しいです。 - スペースとCが一致しないので、検索語は後方いきます。この場合には、一致した文字の数は、2(「AB」)、「一致する値の一部」に対応する、0です。したがって、シフトビット数= 2--0、結果は後方に2件の検索語シフト、2です。
10.スペースは、継続的なシフトの後、Aと一致していませんので。
-
ビット単位の比較、CとDの発見は一致していないまで。次に、シフトビット数= 6--2、検索語は、後方に4を移動し続けます。
-
ビット単位の比較は、検索語、完全一致の最後のビットは、その探索が完了するまで。あなたも検索を続けたい(すなわち、すべてのマッチングを見つける。)、中央値= 7-0を移動し、その後7後方に移動する単語を検索する場合、ここでそれを繰り返すことはしません。
-
どのような「部分一致テーブル」を導入することは接頭辞、接尾辞を生成する方法について説明します
「部分一致値は」「接頭辞」と最長共通要素の「接尾語」の長さです。
例えば、「ABCDABD」の
「A」接頭辞と接尾辞空集合は、共通の要素の長さが0であり;
接頭語「AB」であり、[A]、サフィックスは、共通の要素の長さは0であり、[B]は、
「 ABC "プレフィックスが[AB]、サフィックス[BC、C]、0の共通要素の長さであり、
"プレフィックスABCD「【、AB、ABC]、サフィックス[BCD、CD、D]の合計であります要素の長さが0であり、
接頭辞"ABCDA"がある[、AB、ABC、ABCD ]、 サフィックス[BCDA、CDA、DA、A ]、 ";"、長さ1の共通要素
の接頭辞"ABCDAB" 【、AB、ABC、ABCDであり 、ABCDA]、 サフィックス[BCDABは、CDAB、DAB、AB 、B]、 "AB"、2の長さの共通要素、
接頭辞"ABCDABD"である[、AB、ABC 、ABCD、ABCDA、ABCDAB]、サフィックス[BCDABD、CDABD、DABD、ABD 、BD、D]は、 0は、共通要素の長さです。
- 本質的には「部分一致」は、時々、頭と尾の文字列が繰り返されます。
例えば、二つの「AB」、それは「部分一致する値」に「ABCDABは」2(長さ「AB」)です。検索ワードを移動するときは、最初に「AB」後進4(文字列の長さ - 部分一致値)は、あなたは、第二の「AB」の位置に来ることができます。
コードの実装
package algorithm;
import java.util.Arrays;
/**
* @author 陌生人
* @version V1.0
* @Title:
* @Package
* @Description: (用一句话描述该文件做什么)
* @date:
*/
public class KMPAlgorithm {
public static void main(String[] args) {
String str1 = "BBCABCDABABCDABCDABDE";
String str2 = "ABCDABD";
//Stringstr2="BBC";
int[] next = kmpNext("ABCDABD");//[0,1,2,0]
System.out.println("next=" + Arrays.toString(next));
int index = kmpSearch(str1, str2, next);
System.out.println("index=" + index);//15了
}
public static int kmpSearch(String str1, String str2, int[] next) {
//遍历
for (int i = 0, j = 0; i < str1.length(); i++) {
//需要处理
// str1.charAt(i)!=str2.charAt(j),去调整j的大小
// KMP算法核心点,可以验证...
while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
j = next[j - 1];
}
if (str1.charAt(i) == str2.charAt(j)) {
j++;
}
if (j == str2.length()) {//找到了//j=3i
return i - j + 1;
}
}
return -1;
}
//获取到一个字符串(子串)的部分匹配值表
public static int[] kmpNext(String dest) {
//创建一个next数组保存部分匹配值
int[] next = new int[dest.length()];
next[0] = 0;
//如果字符串是长度为1部分匹配值就是0
for (int i = 1, j = 0; i < dest.length(); i++) {
//当dest.charAt(i)!=dest.charAt(j),我们需要从next[j-1]获取新的j
// 直到我们发现有dest.charAt(i)==dest.charAt(j)成立才退出
// 这时kmp算法的核心点
while (j > 0 && dest.charAt(i) != dest.charAt(j)) {
j = next[j - 1];
}
//当dest.charAt(i)==dest.charAt(j)满足时,部分匹配值就是+1
if (dest.charAt(i) == dest.charAt(j)) {
j++;
}
next[i] = j;
}
return next;
}
}
パートナーとして、JAVAを長い道のり!!!