求一个字符串中是否包含另一个字符串;
最直接的办法就是通过朴素匹配法,其时间复杂度为O(n*m)
public int indexOf(String source, String pattern) {
int i = 0, j = 0;
int sLen = source.length(), pLen = pattern.length();
char[] src = source.toCharArray();
char[] ptn = pattern.toCharArray();
while (i < sLen && j < pLen) {
if (src[i] == ptn[j]) {
// 如果当前字符匹配成功,则将两者各自增1,继续比较后面的字符
i++;
j++;
} else {
// 如果当前字符匹配不成功,则i回溯到此次匹配最开始的位置+1处,也就是i = i - j + 1
// (因为i,j是同步增长的), j = 0;
i = i - j + 1;
j = 0;
}
}
// 匹配成功,则返回模式字符串在原字符串中首次出现的位置;否则返回-1
if (j == pLen)
return i - j;
else
return -1;
}
另一种高效的方法就是KMP算法,难点在于求模式匹配,具体的实现如下:
public class KMPTest {
/**
* 求出一个字符数组的next数组
* @param t 字符数组
* @return next数组
*/
public static int[] getNextArray(char[] t) {
int[] next = new int[t.length];
next[0] = -1;
next[1] = 0;
int k;
for (int j = 2; j < t.length; j++) {
k = next[j - 1];
while (k != -1) {
if (t[j - 1] == t[k]) {
next[j] = k + 1;
break;
} else {
k = next[k];
next[j] = 0; //当k==-1而跳出循环时,next[j] = 0,否则next[j]会在break之前被赋值
}
}
}
return next;
}
// 新的求前缀后缀的方法
public int[] getNext(char[] t){
int[] next = new int[t.length+1];
int j = 0, k= 0;
next[0] = -1;
while(j < t.length-1){
if(k == -1 || t[k] == t[j]){
j++;
k++;
next[j] = k;
}else
k = next[k];
}
}
public static int kmpMatch(String s, String t) {
char[] s_arr = s.toCharArray();
char[] t_arr = t.toCharArray();
int[] next = getNextArray(t_arr);
int i = 0, j = 0;
while (i < s_arr.length && j < t_arr.length) {
if (j == -1 || s_arr[i] == t_arr[j]) {
i++;
j++;
} else
j = next[j];
}
if (j == t_arr.length)
return i - j;
else
return -1;
}
public static void main(String[] args) {
System.out.println(kmpMatch("abcabaabaabcacbhgfgghft", "abc"));
}
}