目錄
1、背景
上面是一個LeetCode的算法題:https://leetcode-cn.com/problems/implement-strstr/
2、算法介紹
- MP算法(爆破):遍歷所有情況
- KMP算法:判定如何重新開始查找(尋找對稱字符串)=>遍歷haystack(不回退)
- Sunday算法:判定模式指針回退位置=>遍歷haystack(不回退)
- BM算法:壞字符&好後綴=>從右向左遍歷
- Rabin-Karp算法:計算一段字符串hash與模式字符串比較,若相等帶入check()進行查找=>return true; 查找成功。否則下一個hash匹配,直到放回true。
3、代碼實現
3.1MP算法
class Solution {
public:
int strStr(string haystack, string needle) {
// 初始排除
if(haystack == needle) return 0;
int M = haystack.size();
int N = needle.size();
if (N == 0) return 0;
if(N > M) return -1;
// 遍歷所有情況
for(int i = 0; i < M-N + 1;i++){
int j;
for(j=0;j<N;j++){
if(haystack[i+j] != needle[j]) break;
}
if( j == N) return i;
}
return -1;
}
};
3.2KMP算法
class Solution {
public:
// 尋找對稱個數
int showNext(string s, int target) {
string str1, str2;
int num = 0;
bool status = false;
for(int j = 0;j < target-1;j++){
if(s[j] != s[j+1]){
status = true;
break;
}
}
if(!status){
return target - 1;
}
for (int i = 0; i < target / 2; i++) {
str1 = str1 + s[i];
str2 = s[target - i - 1] + str2;
if (str1 == str2) {
num = str1.size();
}
}
return num;
}
int strStr(string haystack, string needle) {
// 初始排除
if (haystack == needle) return 0;
int target = needle.size();
if (target == 0) return 0;
int len = haystack.size();
if (target > len) return -1;
int i = 0;
int j = 0;
int temp;
// KMP模式指針回退
while (i < len && j < target) {
if (needle[j] != haystack[i]) {
if (i == len - 1) return -1;
if (j == 0) {
i++;
continue;
}
temp = showNext(needle, j);
j = temp ? temp : 0;
}
else {
if (j == target - 1) return i - j;
i++;j++;
}
}
return -1;
}
};
3.3Sunday算法
class Solution {
public:
// 計算偏移量
int calShiftMat(string s , char chr){
int i = -1;
for(int temp = 0; temp < s.size() ; temp++){
if(s[temp] == chr) i = temp;
}
return i;
}
int strStr(string haystack, string needle) {
// 初始排除
if (haystack == needle) return 0;
int target = needle.size();
if (target == 0) return 0;
int len = haystack.size();
if (target > len) return -1;
int i = 0;
int j = 0;
int temp = 0;
while(i < len && j < target){
if(haystack[i] != needle[j]){
if (i == len - 1) return -1;
if(j == 0){
i++;
continue;
}else{
if(i + target - j > len) return -1;
temp = calShiftMat(needle,haystack[i + target - j]);
if(temp == -1){
i++;
}else{
i +=target - j - temp;
j = 0;
}
}
}else{
if (j == target - 1) return i - j;
i++;
j++;
}
}
return -1;
}
};
3.4BM算法
class Solution {
public:
// 尋找模式指針回退位置
int findChr(string needle , char chr , int j){
for(int i=j - 1; i >= 0; i--){
if(chr == needle[i]) return i + 1;
}
return 0;
}
// BM算法
int strStr(string haystack, string needle) {
// 基本排除
int target = needle.size();
if (target == 0) return 0;
int len = haystack.size();
if (target > len) return -1;
int i = target - 1;
int j = target - 1;
while(i < len && j >= 0){
if(haystack[i] == needle[j]){
if(j == 0) return i;
j--;
i--;
continue;
}
if( i == len -1) return -1;
if(findChr(needle,haystack[i],j) == 0){
i += target;
j = target - 1;
continue;
}
if(j > findChr(needle,haystack[i],j) - 1){
i += target - findChr(needle,haystack[i],j);
j = target - 1;
}
}
return -1;
}
};
3.5Rabin-Karp算法
class Solution {
public:
// 計算hash
int hash(string key , int j , int len){
int sum = 0;
for(int i = 0; i < len; i++){
sum += key[j + i];
}
return sum;
}
// 衝突檢查
bool check(string haystack , string needle , int address){
for(int i = 0; i < needle.size(); i++){
if(haystack[i + address] != needle[i]) return false;
}
return true;
}
// Rabin-Karp算法
int strStr(string haystack, string needle) {
// 基本排除
if(haystack == needle) return 0;
int target = needle.size();
if (target == 0) return 0;
int len = haystack.size();
if (target > len) return -1;
// 模式字符串hash
int temp = hash(needle,0,target);
int result = 0;
int i = 0;
while(i < len - target + 1){
result = hash(haystack,i,target);
if(result == temp){
if(check(haystack,needle,i)){
return i;
}
}
i++;
}
return -1;
}
};