BF(Brute Force)算法:暴力匹配
字符串A为主串,字符串B为模式串
A串从第0位开始,截取B长度的字符串,然后跟B串比较,不匹配的话+1从第1位截取B长度的字符串再比较。。。一直到超过长度
A=HelloWorld
B=Workd
第一次截取到Hello和World比较,不匹配
第二次截取到elloW和world比较,不匹配
第三次截取到lloWo。。。。
。。。
代码实现
public class Bfalth {
public static boolean isMatch(String main, String sub) {
for (int i = 0; i <= (main.length() - sub.length()); i++) {
// 循环截取比较
if (main.substring(i, i + sub.length()).equals(sub)) {
return true;
}
}
return false;
}
public static void main(String[] args) {
System.out.println(isMatch("HelloWorld", "World"));
}
}
Rk(Rabin-Karp)算法
n:为主串长度
m:为匹配串长度
通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了(这里先不考虑哈希冲突的问题)。因为哈希值是一个数字,数字之间比较是否相等是非常快速的,所以模 式串和子串比较的效率就提高了
设计一个hash算法: 将字符串转化成整数,利用K进制的方式
数字1-0 : 10进制(K=10)
123=10101+10*2+3
小写字母a-z:26进制
大小写字母a-Z:52进制
大小写字母+1-0:62进制
字符串“abc”转化成hash值的算法是: a的ASCII码是97
b的ASCII码是98 c的ASCII码是99
972626+98*26+99=68219
偏移97
(97-97)2626+(98-97)*26+(99-97)=68219
代码实现
public class RKalth {
public static boolean isMatch(String main, String sub) {
//算出子串的hash值
int hash_sub = strToHash(sub);
for (int i = 0; i <= (main.length() - sub.length()); i++) {
// 主串截串后与子串的hash值比较
if (hash_sub == strToHash(main.substring(i, i + sub.length()))) {
return true;
}
}
return false;
}
/**
* 支持 a-z 二十六进制 * 获得字符串的hash值
* @param src
*
* @return
*/
public static int strToHash(String src) {
int hash = 0;
for (int i = 0; i < src.length(); i++) {
hash *= 26;
hash += src.charAt(i) - 97;
}
return hash;
}
public static void main(String[] args) {
System.out.println(isMatch("HelloWorld", "World"));
}
}
BM(Boyer-Moore)算法:滑动算法
坏字符规则:
它是按照模式串下标从大到小的顺序,倒着匹配的
我们从模式串的末尾往前倒着匹配,当我们发现某个字符没法匹配的时候。我们把这个没有匹配的字符叫作坏字符(主串中的字符)。
字符 c 与模式串中的任何字符都不可能匹配。这个时候,我们可以将模式串直接往后滑动三位,将模式 串滑动到 c 后面的位置,再从模式串的末尾字符开始比较。
滑动到新位置后,a成了新的坏字符,坏字符 a 在模式串中是存在的,模式串中下标是 0 的位置也是字符 a。这种情况下,我们可以将模式串 往后滑动两位,让两个 a 上下对齐,然后再从模式串的末尾字符开始,重新匹配。
当发生不匹配的时候,我们把坏字符对应的模式串中的字符下标记作 si。如果坏字符在模式串中存在, 我们把这个坏字符在模式串中的下标记作 xi。如果不存在,我们把 xi 记作 -1。那模式串往后移动的位 数就等于 。(下标,都是字符在模式串的下标)
第一次移动3位
c在模式串中不存在,所以 xi=-1 ,移动位数n=2-(-1)=3
第二次移动2位
a在模式串中存在,xi=0 ,移动位数n=2-0=2
代码实现
public class BMalth {
private static final int SIZE = 256; // 全局变量或成员变量
/**
* @param b
* @param m
* @param dc
*/
private static void generateBC(char[] b, int m, int[] dc) {
for (int i = 0; i < SIZE; ++i) {
dc[i] = -1; // 初始化 bc 模式串中没有的字符值都是-1
}
//将模式串中的字符希写入到字典中
for (int i = 0; i < m; ++i) {
int ascii = (int) b[i]; // 计算 b[i] 的 ASCII 值
dc[ascii] = i;
}
}
/**
* 坏字符
*
* @param a 主串
* @param b 模式串
* @return
*/
public static int bad(char[] a, char[] b) {
//主串长度
int n = a.length;
//模式串长度
int m = b.length;
//创建字典
int[] bc = new int[SIZE];
// 构建坏字符哈希表,记录模式串中每个字符最后出现的位置
generateBC(b, m, bc);
// i表示主串与模式串对齐的第一个字符
int i = 0;
while (i <= n - m) {
int j;
for (j = m - 1; j >= 0; --j) {// 模式串从后往前匹配
//i+j : 不匹配的位置
if (a[i + j] != b[j]) {
break;
}
// 坏字符对应模式串中的下标是j
}
if (j < 0) {
return i; // 匹配成功,返回主串与模式串第一个匹配的字符的位置
}
// 这里等同于将模式串往后滑动j-bc[(int)a[i+j]]位
// j:si bc[(int)a[i+j]]:xi
i = i + (j - bc[(int) a[i + j]]);
}
return -1;
}
public static void main(String[] args) {
String s1 = "abcabcabc";
String s2 = "bca";
System.out.println(bad(s1.toCharArray(), s2.toCharArray()));
}
}