Kmp 算法

   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;

}

  

 572. 另一棵树的子树 - 力扣(LeetCode)

 暴力方法:枚举头节点和其对比。时间复杂度为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;

}

在匹配的过程中,只要发现目标串,就应该去除,且去除后的剩余字符串拼接后和目标串对比,所以要使用一种合适结构处理——栈:只要发现匹配出目标串就弹出栈,且通过栈找到下一个位置

1367. 二叉树中的链表 - 力扣(LeetCode)

/**
 * 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数组调整

1397. 找到所有好字符串 - 力扣(LeetCode)

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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值