BF算法(暴力匹配算法,也叫樸素匹配算法).性能不是很高。
我們在主串中,檢查起始位置分別是0.1.2…n-m且長度爲n-m+1個子串,看有沒有跟模式串匹配的。(在A中查找B,A就是主串,B就是模式串,且A>B)。最壞的時間複雜度爲O(n*m),
但是實際上,這也是常用的,1.模式串和主串的長度都不會太長,2.算法思想簡單,代碼實現簡單。
package jike;
public class BF {
public static int BF(char[] str,char[] sub){
int i=0,j=0;
while(j<sub.length && i < str.length){
if(str[i] == sub[j]){
i++;j++;
}
else {
i = i-j+1;
j = 0;
}
}
if(j == sub.length){
return i-j;
}
else {
return -1;
}
}
public static void main(String[] args) {
String str = "abcababcabc";
String sub = "abcabc";
char[] ch1 = str.toCharArray();
char[] ch2 = sub.toCharArray();
int index = BF(ch1,ch2);
System.out.println("輸出主串str:"+str);
System.out.println("輸出子串sub:"+sub);
System.out.println("已找到,對應的主串下標爲:"+index);
}
}
RK算法,RK全稱是(Rabin-Karp)算法。
RK 算法的思路是這樣的:我們通過哈希算法對主串中的 n-m+1 個子串分別求哈希值,然後逐個與模式串的哈希值比較大小。如果某個子串的哈希值與模式串相等,那就說明對應的子串和模式串匹配了(這裏先不考慮哈希衝突的問題,後面我們會講到)。因爲哈希值是一個數字,數字之間比較是否相等是非常快速的,所以模式串和子串比較的效率就提高了。
package jike;
/**
* 字符串匹配RK算法,BF算法的升級版本
*/
public class RK {
/**
* 假設只匹配字母,所以d等於26
* @param str 主串
*/
public static int rabinKarp(String str, String pattern){
int size1 = str.length();
int size2 = pattern.length();
//哈希時需要用到進制計算,這裏只涉及26個字母所以使用26進制
int d = 26;
//防止hash之後的值超出int範圍,對最後的hash值取模
//q取隨機素數,滿足q*d < INT_MAX即可
int q = 144451;
//str子串的hash值
int strCode = str.charAt(0) - 'a';
//pattern的hash值
int patternCode = pattern.charAt(0) - 'a';
//d的size2-1次冪,hash計算時,公式中會用到
int h = 1;
//計算sCode、pCode、h
for (int i = 1; i < size2; i++) {
patternCode = (d*patternCode + pattern.charAt(i)-'a') % q;
//計算str第一個子串的hash
strCode = (d*strCode + str.charAt(i)-'a') % q;
h = (h*d) % q;
}
//最大需要匹配的次數
int frequency = size1 - size2 + 1;
//字符串開始匹配,對patternCode和strCode開始比較,並更新strCode的值
for (int i = 0; i < frequency; i++) {
if(strCode == patternCode && ensureMatching(i, str, pattern)){
return i;
}
//更新strCode的值,即計算str[i+1,i+m-1]子串的hashCode
strCode = ((strCode - h*(str.charAt(i)-'a'))*d + str.charAt(i+size2) - 'a');
}
return -1;
}
/**
* hash值一樣並不能完全確保字符串一致,所以還需要進一步確認
* @param i hash值相同時字符串比對的位置
*/
private static boolean ensureMatching(int i, String str, String pattern) {
String strSub = str.substring(i, i+pattern.length());
return strSub.equals(pattern);
}
public static void main(String[] args) {
String str = "abcabcabc";
String pattern = "cabc";
System.out.println("第一次出現的位置:" + rabinKarp(str, pattern));
}
}