KMPアルゴリズム------文字列照合の問題

KMPアルゴリズム

アプリケーションシナリオ-文字列照合の問題

文字列str1 = "河南ヘナンソフトウェア大学、河南科学技術大学、河南科学技術大学"およびstr2 = "河南科学技術大学"があります。

ここで、str1にstr2が含まれているかどうかを判断する必要があります。存在する場合は、最初に出現した位置を返します。含まれていない場合は、-1を返します。

これは文字列照合の問題の多くの例です

私たちが最初に考えるのは暴力的なマッチングです

暴力的なマッチングのアイデアを使用し、str1がi位置に一​​致し、部分文字列str2がj位置に一致すると仮定すると、次のようになります。

1.現在の文字が正常に一致した場合(つまり、str1 [i] == str2 [j])、i ++、j ++は、引き続き次の文字と一致します。

2.不一致がある場合(つまり、str1 [i]!= str2 [j])、i = i-(j-1)およびj = 0に設定します。一致が失敗するたびに、iが戻り、jが0に設定されます

3.暴力的な方法で解決すると、バックトラックが多くなり、一度に1ビットしか移動しません。一致しない場合は、次の方法に移動して判断し、多くの時間を無駄にします。(現実的ではありません!)

package 字符串匹配问题;
public class ViolenceMatch {
    
    
	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		String str1 = "河南河南软件河南大学河南科技大学软件学院";
		String str2 = "河南科技大学";
		int index = violenceMatch(str1, str2);
		System.out.println(index);
	}
	//暴力匹配算法
	public static int violenceMatch(String str1,String str2){
    
    
		char[] s1 = str1.toCharArray();
		char[] s2 = str2.toCharArray();
		
		int s1Len = s1.length;
		int s2Len = s2.length;
		
		int i = 0;//指向s1
		int j = 0;//指向s2
		while(i<s1Len && j<s2Len){
    
    //保证匹配不越界
			if(s1[i] == s2[j]){
    
    
				//匹配成功
				i++;
				j++;
			}else{
    
    
				i = i - (j-1);
				j = 0;
			}
		}
		//判断是否匹配成功
		if(j == s2Len){
    
    
			return i - j;
		}else{
    
    
			return -1;
		}
	}
}

KMPアルゴリズムの紹介

KMPは、パターン文字列がテキスト文字列に表示されているかどうか、および表示されている場合は最も早い位置にあるかどうかを解決するための古典的なアルゴリズムです。

アルゴリズムは、情報を通じてKMPの方法を用いて決定される前に、次の配列を介して最長共通サブ縦ストリングパターンの長さが格納され大を排除する、整合位置の前面上、次を見つけるために、アレイずつバックを計算時間

ケーススタディ

文字列str1 = "BBC ABCDAB ABCDABCDABDE"と、部分文字列str2 = "ABCDABD"があります

ここで、str1にstr2が含まれているかどうかを判断する必要があります。存在する場合は、最初に出現した位置を返します。含まれていない場合は、-1を返します。
要件:単純なブルートフォースマッチングアルゴリズムではなく、KMPアルゴリズムを使用して判断を完了します。

私はテキストナレーションのプロセスを書きません。結局のところ、多くの大物がそれを非常に明確に書いています。ここに興味があれば、それを検索できます。私は老人へのリンクを投稿しましたhttps://blog.csdn.net/ dark_cy / article / details / 88698736

package 字符串匹配问题;
import java.util.Arrays;
public class KMPAlgorithm {
    
    

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		String str1 = "BBC ABCDAB ABCDABCDABDE";
		String str2 = "ABCDABD";
		
		int next[] = kmpNext("ABCDABD");  //[0,1]
		System.out.println("next"+Arrays.toString(next));
		int index = kmpSearch(str1, str2, next);
		System.out.println(index);
	}
	
	//获取到一个字符串(子串)的部分匹配值
	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)成立才推出
			while(j > 0 && dest.charAt(i) != dest.charAt(j)){
    
    
				j = next[j-1];
			}
			//当dest.charAt(i) == dest.charAt(j)
			if(dest.charAt(i) == dest.charAt(j)){
    
    
				//部分匹配值就需要+1
				j++;
			}
			next[i] = j;
		}
		return next;
	}
	//写出KMP搜索算法
	/**
	 * 
	 * @param str1			原字符串
	 * @param str2			需要找的子串
	 * @param next			部分匹配表(子串对应的)
	 * @return				找到返回第一次出现的位置,没有匹配到返回-1
	 */
	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)
			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()){
    
    
				//找到了
				return i - j + 1;
			}
		}
		return -1;
	}
}

個人的な理解

KMPアルゴリズムの難しさは、マッチング値のこの部分にあります。これは自分で理解する必要があります。興味のある人はインターネットで検索できます。一般的なマッチング方法と同じように、文字が等しい場合はすべて後方に移動しました。、判断を続けます。ブルートフォース方式との違いは、2つの文字が等しくない場合、ブルートフォースは、一致を開始した位置を開始点の後の位置に配置し、その後、この位置からの一致。、非常に面倒です。KMPアルゴリズムは、部分一致値の戻り値に基づいて再一致の場所を見つけます。この一致値がどのように発生したかを理解していれば、その理由もわかります。その場所に移動したい。一般に、KMPアルゴリズムのコアは、部分一致値と次のコードにあります。

		while(j > 0 && str1.charAt(i) != str2.charAt(j)){
    
    
			j = next[j-1];
		}

つまり、部分文字列が添え字が0より大きい位置に一致し、元の文字列の添え字iを持つ文字が、現在の部分文字列位置jを持つ文字と等しくない場合、再一致する必要があります。この位置はからです。部分一致テーブルの値が取り出されます。つまり、iに対応する元の文字列が逆方向に移動しており、1つの位置にブルートフォースで戻る必要はありませんでした。

おすすめ

転載: blog.csdn.net/qq_22155255/article/details/113888417