link: https://leetcode.com/problems/implement-strstr/
Solution 1:寻找substring
class Solution {
public int strStr(String haystack, String needle) {
// needle is empty
if(needle.length() == 0 || needle == null) {
return 0;
}
// haystack is empty
if(haystack.length() == 0 || haystack == null) {
return -1;
}
int index = 0;
int needleLen = needle.length(), hayLen = haystack.length();
for(int i=0; i<hayLen-needleLen+1; i++) { // 当haystack比needle长的时候
String temp = haystack.substring(i, i+needleLen);
if(temp.equals(needle)){
return i;
}
}
return -1;
}
}
TC: O((lenH-lenN)*lenN)
SC: O(1)
Solution 2: 双指针
先找到第一个匹配的字符
计算最长匹配字符串的长度
如果该长度等于needle长度,则输出
否则重新移动指针
Note:需要注意指针在回溯时的位置,和最大位置限制
class Solution {
public int strStr(String haystack, String needle) {
int lenH = haystack.length(), lenN = needle.length();
int ph = 0, pn = 0, currLen = 0;
if(lenN == 0) {
return 0;
}
while(ph < lenH-lenN+1) {
// Find first match char
while(ph < lenH-lenN+1 && haystack.charAt(ph) != needle.charAt(pn)) {
ph++;
}
// calculate max length of matched string
while(ph < lenH && pn < lenN && haystack.charAt(ph) == needle.charAt(pn)) {
ph++;
pn++;
currLen++;
}
// compare
if(currLen == lenN) {
return ph-currLen;
} else {
// backtrack
ph = ph-currLen+1;
currLen = 0;
pn = 0;
}
}
return -1;
}
}
TC:
best: O(lenN)
worse: O(lenN*(lenH-lenN))
SC: O(1)
Solution 3: Rabin Karp算法
算法比较两个string的哈希值来判断是否相等
先把字符转化成整数表示,因为有26个字母,所以哈希时选择26作为base(进制)
比较时使用rolling string的办法,如果不匹配,则减去第一个数字的hash再加上最后一个数字的hash
class Solution {
// char to int
public int char2Int(String s, int idx) {
return (int)s.charAt(idx) - (int)'a';
}
public int strStr(String haystack, String needle) {
int lenH = haystack.length(), lenN = needle.length();
long hashH = 0, hashN = 0;
int base = 26;
long mod = (long)Math.pow(2, 31);
if(lenN == 0) return 0;
if(lenH < lenN) return -1;
// compare haystack[0:lenN] and needle[0:lenN]
for(int i=0; i<lenN; i++) {
hashN = (char2Int(needle, i) + base * hashN) % mod;
hashH = ((char2Int(haystack, i)) + base * hashH) % mod;
}
if(hashN == hashH) return 0;
long baseL = 1;
for(int i=0; i<lenN; i++) {
baseL = (baseL * base) % mod;
}
for(int start=1; start<lenH-lenN+1; start++) {
hashH = (hashH * base - char2Int(haystack, start - 1) * baseL + char2Int(haystack, start + lenN - 1)) % mod;
if(hashH == hashN) return start;
}
return -1;
}
}
TC:O(N) (即使是worst case,因为rolling只走一遍haystack中的字符)
SC: O(1)
难点:
- hash值的计算方法:举例a = [0, 1, 2, 3],则hashA = a[0] * 263 + a[1] * 262 + a[2] * 261 + a[3] * 260,学会推导hash的公式
- 由于hash值过大会溢出,因此计算时将hash取模
- rolling时hash的公式推导
Note:
不懂就看leetcode的题解,多看看