java KMP + 字符串哈希两种方法
KMP
KMP不多说了,先计算 n e x t [ ] next[] next[]数组,再逐个匹配即可。
class Solution {
public int strStr(String haystack, String needle) {
if(needle.length() == 0) return 0;
char[] s = haystack.toCharArray(), p = needle.toCharArray();
int[] ne = new int[p.length];
for(int i = 1, j = 0; i < p.length; i++){
while(j > 0 && p[i] != p[j]) j = ne[j - 1];
if(p[i] == p[j]) j++;
ne[i] = j;
}
for(int i = 0, j = 0; i < s.length; i++){
while(j > 0 && s[i] != p[j]) j = ne[j - 1];
if(s[i] == p[j]) j++;
if(j == p.length) return i - p.length + 1;
}
return -1;
}
}
时间复杂度
KMP时间复杂度 O ( n ) O(n) O(n)。
空间复杂度
额外 n e x t [ ] next[] next[]数组,使用 O ( m ) O(m) O(m)额外空间, m m m为匹配串长度。
字符串哈希
计算 h a y s t a c k haystack haystack字符串的哈希前缀和,想要计算任意一段字串的哈希值的时候只需要使用 h [ r ] − h [ l − 1 ] ∗ p [ r − l + 1 ] h[r] - h[l - 1] * p[r - l + 1] h[r]−h[l−1]∗p[r−l+1]公式即可计算,相当于将 [ 0 , l ] [0,l] [0,l]左移 r − l + 1 r-l+1 r−l+1位之后减掉,这样就剩下 [ l , r ] [l,r] [l,r]区间的字符串哈希了。再循环一遍比较每一部分的字符串哈希是否与 n e e d l e needle needle的哈希相同即可。
这里哈希过程中的 P P P值取 31 31 31的原因,是因为 j a v a java java的 S t r i n g . h a s h C o d e ( ) String.hashCode() String.hashCode()方法中,取值为 31 31 31,对标一下,就可以直接使用其 h a s h C o d e ( ) hashCode() hashCode()方法进行计算了。
class Solution {
int P = 31;
int[] h, p;
int get(int l, int r){
return h[r] - h[l - 1] * p[r - l + 1];
}
public int strStr(String haystack, String needle) {
if(needle.length() == 0) return 0;
h = new int[haystack.length() + 1];
p = new int[haystack.length() + 1];
char[] str = haystack.toCharArray();
char[] ptr = needle.toCharArray();
int hashcode = needle.hashCode();
p[0] = 1;
for(int i = 1; i <= str.length; i ++){
h[i] = h[i - 1] * P + str[i - 1];
p[i] = p[i - 1] * P;
}
for(int i = 1; i <= str.length - ptr.length + 1; i++){
if(hashcode == get(i, i + ptr.length - 1)) return i - 1;
}
return -1;
}
}
时间复杂度
O ( n ) O(n) O(n)级别复杂度,两次循环都为 O ( n ) O(n) O(n)。
空间复杂度
O ( n ) O(n) O(n)级别额外空间。