一、寻找子串首次出现的位置
代码:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
///寻找子串首次出现的位置 #include<stdio.h> int a[ 1000010], b[ 10010]; int next[ 10010]; int n, m; void getNext() { ///求next数组 ///j表示前缀(前缀是固定的),i表示后缀(后缀是相对的) int i, j; i = 0; j = - 1; next[ 0] = - 1; while(i < m) { if(j == - 1 || b[i] == b[j]) ///如果可以匹配,都加一进行下一轮匹配 { i++; j++; next[i] = j; } else j = next[j]; ///如果不能匹配,就退回到next[j]; } } ///返回首次出现的位置 int KMP_Index() { int i = 0, j = 0; getNext(); while(i < n && j < m) { if(j == - 1 || a[i] == b[j]) { i++; j++; } else j = next[j]; } if(j == m) return i - m + 1; else return - 1; } int main() { int T; scanf( "%d", &T); while(T--) { scanf( "%d%d", &n, &m); for( int i = 0; i < n; i++) scanf( "%d", &a[i]); for( int i = 0; i < m; i++) scanf( "%d", &b[i]); printf( "%d\n", KMP_Index()); } return 0; } |
二、统计子串出现的个数
代码:
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
///统计子串出现的次数 #include<bits/stdc++.h> using namespace std; char W[ 10010], T[ 1000010]; int wlen, tlen; int next[ 10010]; void getNext() { int i, j; i = 0; j = - 1; next[ 0] = - 1; while(j < wlen) { if(j == - 1 || W[i] == W[j]) { i++; j++; next[i] = j; } else j = next[j]; } } int KMP_count() { int ans = 0; int i, j = 0; if(wlen == 1 && tlen == 1) { if(W[ 0] == T[ 0]) return 1; else return 0; } getNext(); for(i = 0; i < tlen; i++) { while(j > 0 && T[i] != W[j]) j = next[j]; if(W[j] == T[i]) j++; if(j == wlen) { ans++; j = next[j]; } } return ans; } int main() { int tcase; scanf( "%d", &tcase); while(tcase--) { scanf( "%s%s", &W, &T); wlen = strlen(W); tlen = strlen(T); printf( "%d\n", KMP_count()); } return 0; } |
ps:kmp算法的核心就是避免不必要的回溯,那么什么是不必要的呢?问题由模式串决定,不是由目标串决定