假设字符串str长度为N,字符串match长度为M,M <= N
想确定str中是否有某个子串是等于match的。
时间复杂度O(N)
如果一个str,要确定match是否是他的子串,比如从0位置开始匹配,一直匹配,到match最后一位没有匹配到,那么我们就需要从str的1位置继续循环,这是暴力解法.KMP就是对回退做了一个优化.
假如我们的match字符串为 1231234 那么会生成一个next数组
这个数组意思比如你到了match最后一个位置 这个位置值为3,3的含义就是123 123 一样,如果和str不匹配你可以回退到match[3]这个位置继续的str比较,不用回退到match[0]比较 因此时间复杂度才可以减少0n
public static int getIndexOf(String s1, String s2) {
if (s1 == null || s2 == null || s2.length() < 1 || s1.length() < s2.length()) {
return -1;
}
char[] str1 = s1.toCharArray();
char[] str2 = s2.toCharArray();
int x = 0;
int y = 0;
// O(M) m <= n
int[] next = getNextArray(str2);
// O(N)
while (x < str1.length && y < str2.length) {
if (str1[x] == str2[y]) {
x++;
y++;
} else if (next[y] == -1) { // y == 0
x++;
} else {
y = next[y];
}
}
return y == str2.length ? x - y : -1;
}
public static int[] getNextArray(char[] str2) {
if (str2.length == 1) {
return new int[] { -1 };
}
int[] next = new int[str2.length];
next[0] = -1;
next[1] = 0;
int i = 2; // 目前在哪个位置上求next数组的值
int cn = 0; // 当前是哪个位置的值再和i-1位置的字符比较
while (i < next.length) {
if (str2[i - 1] == str2[cn]) { // 配成功的时候
next[i++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[i++] = 0;
}
}
return next;
}
KMP算法变化题
给定两棵二叉树的头节点head1和head2
想知道head1中是否有某个子树的结构和head2完全一样
思路: 树直接先序或者后序遍历,然后再KMP就行
判断str1和str2是否是旋转字符串
思路:旋转就是说 1234 他的旋转就是 1234 2341 3412 4123 那么我可以把str1+str1 然后看这个新的和str2做KMP 即可