18. 用 java 实现 BF 算法、KMP算法

字符串匹配算就是给定两个串,查找一个串是否在另一个串里面。为解决这个问题由此衍生了两个算法,B BF 算法和 KMP 算法。下面就来了解一下这两个算法吧。

1.用java实现 BF 算法

BF算法又称为暴力算法,它的核心思想是:从下标为 0 处比较主串和子串,若相等,则依次向下比较,直到子串结束,则得到匹配结果,若不相等,则主串回溯到下标为 1 处和子串下标为 0 处比较,依次类推,直到得到结果。

优点:比较容易理解,没有对主串和子串进行多余的处理。

缺点:每次每次字符不匹配时,都要回溯到上次比较的下一个位置,时间开销大。

大家可以按照下面的图来理解比较容易一些。




由此我们发现 i 每次走的位置都等于 j 走的位置,所以我们的到 i 拖回的位置为 i-j+1。

下面用 java 实现 BF 算法的代码。

public static int BF(String str,String sub,int pos){
    //1.判断pos合法性。
    if(pos < 0 || pos > str.length()){
        return -1;
    }
    //2.开始查找。
    int i = pos;
    int j = 0;
    //3.遍历主串和子串。
    while(i <str.length() && j <sub.length()){
        if(str.charAt(i) == sub.charAt(j)){
	    i++;
	    j++;
        }else{
	    i = i-j+1;
	    j = 0;
	}
    }
    //4.哪种情况下表示找到
    if(j >= sub.length()){
	return i-j;
    }else{
        return -1;
    }
}	

下面是运算结果:

public static void main(String[] args) {
    String str = "ababcabcdabcde";
    String sub =  "abcd";
    System.out.println(BF(str,sub,0));
}


2.KMP算法

相比于 BF 算法,KMP 算法时间复杂度大大的减小了,主要在于主串不用回溯。但是 KMP 算法非常难理解,需要仔细琢磨。

我们举例来看。



以下是根据KMP算法写出的代码:

public static int Kmp(String str,String sub,int pos){
	int i = pos;
	int j = 0;
	int[] next = new int[sub.length()];
	getNext(next,sub);
	while(i < str.length() && j < sub.length()){
		if(j == -1 || str.charAt(i) == sub.charAt(j)){
			i++;
			j++;
		}else{
			j = next[j];
		}
	}
	if(j >= sub.length()){
		return i-j;
	}else{
		return -1;
	}
}


那么我们如何来找 j 退回的位置呢,这才是 KMP 算法的核心所在。找到 j 的退回位置有如下规则:

找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标 0 开始,另一个以 j-1 下标结尾。

不管什么数据 next[0] = -1;next[1] = 0;

例如上图:主串前面的 ab 和子串开头的 ab 相等,所以我们直接将 j 退回到 c 的位置,然后比较 i 和 j 位置的字符。

为了得到每个 j 返回的位置,我们需要设一个数组 next 来存储 j 返回的位置。

上图的子串对应的数组即为-1,0,0,0,1,2.

我们推导出如下的公式:


下面是根据这个规则写出的代码:

public static void getNext(int[] next,String str){
	next[0] = -1;
	next[1] = 0;
	int i = 2;//下一项
	int k = 0;//前一项的k
	while(i < str.length()){
		if(k == -1||str.charAt(k) == str.charAt(i - 1)){//Pk == Pi时
			next[i] = k + 1;
			i++;
			k = k+1;
		}else{
			k = next[k];
		}
	}
}

如果有什么不当之处请指出。

猜你喜欢

转载自blog.csdn.net/alyson_jm/article/details/80287867