中国矿业大学数据结构实验(2)
A 子串个数
长度为\(n\)的字符串,其子串个数为\(\frac{n(n+1)}{2}+1\)
B KMP
KMP算法
给定一个模式串\(P\)和一个主串\(S\),求模式串\(P\)在主串\(S\)中出现的位置
求\(next[]\)数组
\(next[i]\)表示\(P[1,i]\)中相等前后缀的最长长度,\(i\)扫描模式串,\(j\)扫描前缀
初始化\(next[1]=0\),指针\(i = 2,j=0\)
每轮for循环,\(i\)向右走一步:
\((1)\)若\(P[i] \ne P[j+1]\),则让\(j\)退回到能匹配的值,即\(j=next[j]\),直到为\(0\);
\((2)\)若\(P[i] = P[j+1]\),则让\(j+1\),指向匹配前缀的末尾;
\((3)\)\(next[i]=j\).
next[1] = 0;
int i = 2,j = 0;
for(i,j; i <= n ; i ++){
while(j && P[i] != P[j+1]) j = next[j];
if(P[i] == P[j+1]) j ++;
next[i] = j;
}
说明:假设第\(k+1\)轮循环开始时对应的\(j = j_k\),由于前一次的操作,我们知道\(P[1,j_k]\)是已经匹配的最长前缀,即\(P[1,j_k]=P[k-j_k+1,k]\),分情况讨论:
\((1)\)若\(P[j_k+1]=P[k+1]\),说明\(P[1,j_k]+P[j_k+1]=P[k-j_k+1,k]+P[k+1]\)即\(P[1,j_k+1]=P[k-j_k+1,k+1]\),故\(j_{k+1}=j_k+1\);
\((2)\)若\(P[j_k+1]\ne P[k+1]\),那么\(P[1,j_k]+P[j_k+1]\ne P[k-j_k+1,k]+P[k+1]\),匹配长度无法增加\(1\),而我们已知\([1,k]\)的\(next[]\)值,从之前的操作来看:\(j_k \in [1,k]\),那么\(next[j_k]\)已知,令\(t = next[j_k]\),则有\(P[1,t]=P[j_k-t+1]\).在第\(k\)轮循环后,\(P[1,j_k]=P[k-j_k+1,k]\),那么\(P[k-j_k+1,k-j_k+t]=P[k-t+1,k]\),所以证得\(P[1,t]=P[k-t+1,k]\),比较形式,可得\(j_{k+1}=next[j_k]\),当再次不匹配时,\(j_{k+1}=next[next[j_k]]\),如此循环,直到\(j=0\)或者匹配为止.

模式串与主串匹配
双指针:\(i\)扫描主串,\(j\)扫描模式串,初始化\(i=1,j=0\)
每轮for循环,\(i\)向右走一步:
\((1)\)若\(S[i] \neq P[j+1]\),让\(j\)回跳到能匹配的位置,找不到就回到\(0\);
\((2)\)若\(S[i]=P[j+1]\),让\(j\)向右走一步;
\((3)\)若匹配成功,则输出匹配位置
总共的时间复杂度:\(O(n+m)\)
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1000010;
int m, n;
char S[N], P[N];
int nxt[N];
int main() {
memset(S, 0, sizeof(S));
memset(P, 0, sizeof(P));
cin.getline(S + 1, N - 1);
cin.getline(P + 1, N - 1);
m = strlen(S + 1);
n = strlen(P + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j && P[i] != P[j + 1]) j = nxt[j];
if (P[i] == P[j + 1]) j++;
nxt[i] = j;
}
bool found = false;
for (int i = 1, j = 0; i <= m; i++) {
while (j && S[i] != P[j + 1]) j = nxt[j];
if (S[i] == P[j + 1]) j++;
if (j == n) {
printf("%d\n", i - n + 1);
found = true;
// j = nxt[j];
}
}
if (!found) printf("0\n");
return 0;
}
C
D
E
#include<iostream>
using namespace std;
int cnt = 0;
void dfs(int n, char x, char y, char z)
{
if (n == 1) printf("%d %d %c->%c\n", ++cnt, n, x, z);
else {
dfs(n - 1, x, z, y);
printf("%d %d %c->%c\n", ++cnt, n, x, z);
dfs(n - 1, y, x, z);
}
}
int main()
{
int n;
cin >> n;
dfs(n, 'A', 'B', 'C');
return 0;
}
FG
#include <iostream>
#include <vector>
using namespace std;
const int N = 27;
vector<int> ch[N];
int din[N] = {0};
int vis[N] = {0};
int toi(char c) { return c - 'A' + 1; }
char toc(int a) { return 'A' + (a - 1); }
void dfs(int u, vector<char>& pre, vector<char>& post) {
pre.push_back(toc(u));
for (int v : ch[u]) dfs(v, pre, post);
post.push_back(toc(u));
}
int main() {
char x, y;
while (cin >> x >> y) {
int u = toi(x), v = toi(y);
ch[u].push_back(v);
din[v]++;
vis[u] = vis[v] = 1;
}
int root = -1;
for (int i = 1; i <= 26; i++) {
if (vis[i] && din[i] == 0) {
root = i;
break;
}
}
vector<char> preOrder, postOrder;
dfs(root, preOrder, postOrder);
for (char c : preOrder) cout << c << " ";
for (char c : postOrder) cout << c << " ";
return 0;
}

浙公网安备 33010602011771号