kmp算法代码
时间复杂度为:O(n+m),n和m分别为两个字符串的长度。求解一个位置的next值时间复杂度均摊为O(1);求解s1中1个位置的对比过程均摊的时间复杂度为O(1)
#include <iostream>
#include <vector>
using namespace std;
vector<int>nex;
void f(string t) {//求nex数组
int n = t.size();
nex.assign(n, 0);
if (n == 1) {
nex[0] = -1;
return;
}
nex[0] = -1;
nex[1] = 0;
int i = 2, cn = 0;
while (i < n) {
if (t[i - 1] == t[cn])
nex[i++] = ++cn;
else if (cn > 0)
cn = nex[cn];
else nex[i++] = 0;
}
}
int kmp(string s, string t) {
f(t);
int n = s.size(), m = t.size();
int x = 0, y = 0;
while (x < n && y < m) {
if (s[x] == t[y]) {
x++;
y++;
}
else if (y == 0)
x++;
else y = nex[y];
}
return y == m ? x - y : -1;
}
int main() {
string s, t;
cin >> s >> t;
f(t);
cout << kmp(s, t);
return 0;
}
暴力方法:枚举头节点和其对比。时间复杂度为O(n*m);
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
bool issame(TreeNode* root, TreeNode* cur) {
if (root == nullptr && cur == nullptr)
return true;
if (root != nullptr && cur != nullptr)
return root->val == cur->val && issame(root->left, cur->left) &&
issame(root->right, cur->right);
return false;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if (root != nullptr && subRoot != nullptr) {
return issame(root, subRoot) || isSubtree(root->left, subRoot) ||
isSubtree(root->right, subRoot);
}
return subRoot == nullptr;
}
};
kmp转化:树可以通过先序遍历转化为先序序列,然后kmp求子串出现的位置
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
vector<int> nex;
void f(vector<string>& s, TreeNode* cur) {
if (cur == nullptr) {
s.push_back("null");
return;
}
s.push_back(to_string(cur->val));
f(s, cur->left);
f(s, cur->right);
}
void get_nex(vector<string>& t) {
int n = t.size();
if (n == 1) {
nex[0] = -1;
return;
}
nex[0] = -1;
nex[1] = 0;
int x = 2, cn = 0;
while (x < n) {
if (t[x - 1] == t[cn]) {
nex[x++] = ++cn;
} else if (cn > 0)
cn = nex[cn];
else
nex[x++] = 0;
}
}
int kmp(vector<string>& s, vector<string>& t) {
int n = s.size();
int m = t.size();
nex.assign(m, 0);
get_nex(t);
int x = 0, y = 0;
while (x < n && y < m) {
if (s[x] == t[y]) {
x++;
y++;
} else if (y == 0)
x++;
else
y = nex[y];
}
return y == m ? x - y : -1;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if (root != nullptr && subRoot != nullptr) {
vector<string> s;
vector<string> t;
f(s, root);
f(t, subRoot);
int ans = kmp(s, t);
return ans != -1;
}
return subRoot == nullptr;
}
};
P4391 [BOI2009] Radio Transmission 无线传输 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
求出字符串的最长相同前后缀长度,总长度减去其就是循环节
#include <iostream>
#include <vector>
using namespace std;
vector<int>nex;
void get_nex(string s) {
int n = s.size();
nex.assign(n+1, 0);
nex[0] = -1;
if (n == 1)
return;
nex[1] = 0;
int cn = 0;
int i = 2;
while (i <= n) {
if (s[i-1] == s[cn]) {
nex[i++] = ++cn;
}
else if (cn > 0)
cn = nex[cn];
else nex[i++] = 0;
}
}
int main() {
int n;
cin >> n;
string s;
cin >> s;
get_nex(s);
int len = nex[n];
cout << n - len;
return 0;
}
P4824 [USACO15FEB] Censoring S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <iostream>
#include <vector>
using namespace std;
vector<int>nex;
static const int maxn = 1000001;
int stack1[maxn];
int stack2[maxn];
void get_nex(string s) {
int n = s.size();
nex.assign(n,0);
nex[0] = -1;
nex[1] = 0;
int i = 2, cn = 0;
while (i < n) {
if (s[i-1] == s[cn])
nex[i++] = ++cn;
else if (cn > 0)
cn = nex[cn];
else nex[i++] = 0;
}
}
void f(string s, string t) {
get_nex(t);
int x = 0, y = 0;
int n = s.size();
int m=t.size();
int size = 0;
while (x < n) {
if (s[x] == t[y]) {
stack1[size] = x;
stack2[size] =y;
size++;
x++;
y++;
}
else if (y == 0) {
stack1[size] = x;
stack2[size] = -1;
size++;
x++;
}
else {
y = nex[y];
}
if (y == m) {
size -=m;
y = size > 0 ? (stack2[size - 1] + 1) : 0;
}
}
for (int i = 0; i < size; i++)
cout << s[stack1[i]];
return;
}
int main() {
string s, t;
cin >> s >> t;
f(s, t);
return 0;
}
在匹配的过程中,只要发现目标串,就应该去除,且去除后的剩余字符串拼接后和目标串对比,所以要使用一种合适结构处理——栈:只要发现匹配出目标串就弹出栈,且通过栈找到下一个位置
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left),
* right(right) {}
* };
*/
class Solution {
public:
vector<int> child;
vector<int> nex;
void get_nex() {
int n = child.size();
nex.assign(n, 0);
nex[0] = -1;
if (n == 1)
return;
nex[1] = 0;
int i = 2, cn = 0;
while (i < n) {
if (child[i - 1] == child[cn]) {
nex[i++] = ++cn;
} else if (cn > 0)
cn = nex[cn];
else
nex[i++] = 0;
}
}
bool f(TreeNode* root, int i) {
if (i == child.size())
return true;
if (root == nullptr)
return false;
int cur = (root->val);
while (i >= 0 && cur != child[i]) {
i = nex[i];
}
return f(root->left, i + 1) || f(root->right, i + 1);
}
bool isSubPath(ListNode* head, TreeNode* root) {
child.clear();
while (head != nullptr) {
child.push_back(head->val);
head = head->next;
}
get_nex();
return f(root, 0);
}
};
将链表的数字拿出形成一个数组,然后遍历树和数组对应,如果对应不上就通过nex数组调整
class Solution {
public:
static const int mod = 1000000007;
static const int maxm = 501;
static const int m = 51;
vector<int> nex;
int dp[maxm][m][2];
void get_nex(string s) {
int n = s.size();
nex.assign(n, 0);
nex[0] = -1;
if (n == 1)
return;
nex[1] = 0;
int i = 2, cn = 0;
while (i < n) {
if (s[i - 1] == s[cn])
nex[i++] = ++cn;
else if (cn > 0)
cn = nex[cn];
else
nex[i++] = 0;
}
}
int jump(char a, string evil, int j) {
while (j >= 0 && evil[j] != a)
j = nex[j];
return j;
}
int f(string s, string evil, int n, int m, int i, int j, int free) {
if (j == m)
return 0;
if (i == n)
return 1;
if (dp[i][j][free] != -1)
return dp[i][j][free];
char cur = s[i];
int ans = 0;
if (free == 0) {
for (char c = 'a'; c < cur; c++) {
ans = (ans + f(s, evil, n, m, i + 1, jump(c, evil, j) + 1, 1)) %
mod;
}
ans = (ans + f(s, evil, n, m, i + 1, jump(cur, evil, j) + 1, 0)) %
mod;
} else {
for (char c = 'a'; c <= 'z'; c++) {
ans = (ans + f(s, evil, n, m, i + 1, jump(c, evil, j) + 1, 1)) %
mod;
}
}
dp[i][j][free] = ans;
return ans;
}
int iskmp(string s, string evil) {
int x = 0, y = 0;
int n = s.size(), m = evil.size();
while (x < n && y < m) {
if (s[x] == evil[y]) {
x++;
y++;
} else if (y == 0)
x++;
else
y = nex[y];
}
return y == m ? x - y : -1;
}
int findGoodStrings(int n, string s1, string s2, string evil) {
get_nex(evil);
memset(dp, -1, sizeof(dp));
int a1 = f(s1, evil, s1.size(), evil.size(), 0, 0, 0);
memset(dp, -1, sizeof(dp));
int a2 = f(s2, evil, s2.size(), evil.size(), 0, 0, 0);
bool spec = (iskmp(s1, evil) != -1);
int ans = ((a2 - a1 + mod) % mod + (spec ? 0 : 1) % mod) % mod;
return ans;
}
};
如果没有evil这个条件,就是单纯的数位dp问题;如果有evil这个条件,就在枚举的时候通过next数组对比调整,如果之前选的字母和evil字符串配对了,就返回0。