我们先计算 target 的 hashcode,然后用 source 中相同长短子字符串的hashcode与其相比,既可以过滤掉绝大多数不匹配的情况。具体实现中,可以想象用一个长度等于 len(target) 的 window 从左向右移动,每次加入右边字符,减去左边字符,然后和 targetCode比较。
class Solution {
private final int BASE = 1000000;
public int strStr(String haystack, String needle) {
if (haystack == null || needle == null) return -1;
else if (needle.length() == 0) return 0;
int targetCode = getHashCode(needle);
int factor = getFactor(needle.length());
// sliding window
int left = 0, right = -1, windowCode = 0;
while (right < haystack.length()) {
while (right - left + 1 < needle.length()) {
right++;
if (right == haystack.length()) return -1;
windowCode = (windowCode * 31 + haystack.charAt(right) % 31) % BASE;
}
if (windowCode == targetCode) {
if (haystack.substring(left, right + 1).equals(needle)) return left;
}
// move left pointer
windowCode = windowCode - (haystack.charAt(left) % 31 * factor) % BASE;
if (windowCode < 0) windowCode += BASE;
left++;
}
return -1;
}
// calculate the hashcode of needle
private int getHashCode(String target) {
int code = 0;
for (int i = 0; i < target.length(); ++i) {
code = (code * 31 + target.charAt(i) % 31) % BASE;
}
return code;
}
// calculate the factor of the leftmost character in the window
private int getFactor(int windowSize) {
int factor = 1;
for (int i = 0; i < windowSize - 1; ++i) {
factor = factor * 31 % BASE;
}
return factor;
}
}