一、寻找子串首次出现的位置
代码:
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算法的核心就是避免不必要的回溯,那么什么是不必要的呢?问题由模式串决定,不是由目标串决定

被折叠的 条评论
为什么被折叠?



