ACM - 字符串 - 基础(KMP)

这篇具有很好参考价值的文章主要介绍了ACM - 字符串 - 基础(KMP)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、KMP

1、模板题 HDU1711 Number Sequence

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711
ACM - 字符串 - 基础(KMP)
题目大意
找出子串第一次出现的位置,找不到输出 - 1.

next 数组的含义:
next [ i ] 表示:以 i 为终点,以 1 为起点,前后缀能一致的最长字串。
(在某些头文件有命名过next,所以代码里面以 ne 代表next)

next [ i ] = x 表示:如果匹配到 idx = i 的时候 str [ i ] != p [ i ],那么在 str
第 i 个字符的前面有 x 个字符不用再重新匹配,可以直接拿 str [ i ] 和 p [ x + 1 ] 开始比较,循环往复。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rit int t; scanf("%d", &t)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 1000010, M = 10010; 

//(val & 1) == 0偶, == 1奇。
int str[N];  //文本串
int p[M];   //匹配串 
int ne[M]; //next数组

//获得匹配串的next数组
void make_nextArr(int m) {
	MEM(ne, 0);
	for (int i = 2, j = 0; i <= m; ++ i) {
		//获得当前的 i 能和 p 数组里面最右的哪个数匹配
		while (j && p[i] != p[j + 1]) j = ne[j]; 
		//能匹配则 if 为真
		if (p[i] == p[j + 1]) ++ j;
		//记录到ne数组
		ne[i] = j;
	}
} 

//kmp的过程
void KMP (int n, int m) {
	bool flag = true;
	for (int i = 1, j = 0; i <= n; ++ i) {
		while (j && str[i] != p[j + 1]) j = ne[j];
		if (str[i] == p[j + 1]) ++ j; 
		if (j == m) {  //j == m 说明匹配到公共子串了
			pr("%d\n", i - m + 1);
			flag = false;
			break;
		}
	}
	if (flag) pr("-1\n");
}

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	//freopen("D:\\out.txt", "w", stdout);
	rit;
	while (t --) {
		int n, m;
		sc("%d %d", &n, &m);
		for (int i = 1; i <= n; ++ i) sc("%d", &str[i]);
		for (int i = 1; i <= m; ++ i) sc("%d", &p[i]);
		
		make_nextArr(m);
		
		KMP(n, m);
		
	}
	return 0;
}

2、求最大匹配数 Ⅰ: HDU 2087 剪花布条(子串不重叠)

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087

ACM - 字符串 - 基础(KMP)
题目大意
找到子串最大数目,子串间不可重叠。

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rit int t; scanf("%d", &t)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 1010; 

//(val & 1) == 0偶, == 1奇。

char str[N], p[N];
int ne[N];
int cnt;

void make_next(int m) {
	for (int i = 2, j = 0; i <= m; ++ i) {
		while (j && p[i] != p[j + 1]) j = ne[j];
		if(p[i] == p[j + 1]) ++ j;
		ne[i] = j;
	}
}

//在下标为 start 的地方开始kmp
void KMP (int n, int start, int m) {
	if (start > n) return; // 开始的下标不合法即结束
	int i = start;
	for (int j = 0; i <= n; ++ i) {
		while (j && str[i] != p[j + 1]) j = ne[j];
		if (str[i] == p[j + 1]) ++ j;
		if (j == m) {
			++ cnt;
			break;
		}	
	}
	KMP(n, i + 1, m); //递归获得最大匹配次数
}


int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	//freopen("D:\\out.txt", "w", stdout);
	str[0] = 6, p[0] = 6; //防止 strlen 为 0 
	while (true) {
		sc("%s", str + 1);
		getchar();
		int n = strlen(str) - 1;
		if (n == 1 && str[1] == '#')  break;
		sc("%s", p + 1);
		int m = strlen(p) - 1;
		
		make_next(m);
		
		cnt = 0;  //记得置零
		KMP(n, 0, m);
		pr("%d\n", cnt);
	}
	return 0;
}

3、求最大匹配数 Ⅱ:AcWing 831. KMP字符串(子串可重叠)

原题链接:https://www.acwing.com/problem/content/description/833/
ACM - 字符串 - 基础(KMP)
思路
主要是在kmp的时候,当找到和模板串一模一样的子串时,直接让 j = ne [ j ] ,否则对于一些苛刻的数据会超时,例如字符串全是同一个字符的时候。

代码

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define getlen(array) {return (sizeof(array) / sizeof(array[0]));}
#define ll long long 
#define MEM(x, y) memset(x, y, sizeof x)
#define rin int n; scanf("%d", &n)
#define rln ll n; scanf("%lld", &n)
#define rit int t; scanf("%d", &t)
#define ria int a; scanf("%d", &a)
#define sc scanf
#define pr printf

const int INF = 0x3f3f3f3f;
const int N = 100010, M = 1000010; 

//(val & 1) == 0偶, == 1奇。

char p[N], s[M];
int ne[N];

void get_next(int length) {
    for (int i = 2, j = 0; i <= length; ++ i) {
        while (j && p[i] != p[j + 1]) j  = ne[j];
        if (p[i] == p[j + 1]) ++ j;
        ne[i] = j;
    }
}

void kmp(int n, int a) {
    for (int i = 1, j = 0; i <= a; ++ i) {
        while (j && s[i] != p[j + 1]) j = ne[j];
        if (s[i] == p[j + 1]) ++ j;
        if (j == n) {
            pr("%d ", i - n);
            j = ne[j];  // 最关键步骤
        }
    }
} 

int main() {
	//freopen("D:\\in.txt", "r", stdin); 
	//freopen("D:\\out.txt", "w", stdout);
	rin;
	sc("%s", p + 1);
	ria;
	sc("%s", s + 1);
	get_next(n);
	kmp(n, a);
	return 0;
}

4、s2 是不是 s1 的翻转:Leetcode 面试题 01.09. 字符串轮转

原题链接:https://leetcode-cn.com/problems/string-rotation-lcci/
ACM - 字符串 - 基础(KMP)
思路

这道题目最大的精髓在于将 s2 和 s2相连后,如果 s2 是 s1 翻转后的字符串,那么新拼接而成的字符串一定存在某个字串是 s1,后面的事情就直接 kmp。
(当然也可以直接调用字符串本身的 find 函数……)

代码

kmp 版:

class Solution {
public:
    int ne[100010];
    bool isFlipedString(string s1, string s2) {
        if (s1.size() != s2.size()) return false;
        if (s1 == "" && s2 == "") return true;
        s1 = ' ' + s1;
        s2 = s2 + s2;
        s2 = ' ' + s2;
        get_next(s1);
        return kmp(s1, s2);
    }
    void get_next(string s) {
        for (int i = 2, j = 0; s[i]; ++ i) {
            while (j != 0 && s[i] != s[j + 1]) j = ne[j];
            if (s[i] == s[j + 1]) ++ j;
            ne[i] = j;
        }
    }
    bool kmp(string p, string s) {
        int length = p.size() - 1;
        for (int i = 1, j = 0; s[i]; ++ i) {
            while (j != 0 && s[i] != p[j + 1]) j = ne[j];
            if (s[i] == p[j + 1]) ++ j;
            if (j == length) return true;
        }
        return false;
    }
};

调用函数版:

class Solution {
public:
    bool isFlipedString(string s1, string s2) {
        return s1.size() == s2.size() && (s2 + s2).find(s1) != -1;
    }
};

————————————————————
2021.02.26 学习KMP,匹配数Ⅰ
2021.03.25 KMP匹配数Ⅱ
2021.03.29 KMP - 翻转文章来源地址https://www.toymoban.com/news/detail-445086.html

到了这里,关于ACM - 字符串 - 基础(KMP)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • KMP-重复子字符串

    Problem: 459. 重复的子字符串 给定一个字符串str1, 判断其是否由重复的子串构成。 例子1:输入 str1=‘ababab’ ;输出 true 例子2:输入 str1=‘ababac’ ;输出 false 重复子字符串组成的字符串,其肯定存在一个后缀和前缀是一样的,并且这个后缀其由后缀前面的字符子串组成。所以

    2024年01月25日
    浏览(36)
  • 字符串匹配算法(BF&&KMP)

    个人主页:平行线也会相交 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【数据结构初阶(C实现)】 在学习这个算法之前,我们先来看看什么时字符串匹配算法,简单来说 有一个主串和一个子串,查找子串在主串的位置,然后返回这个位置

    2023年04月17日
    浏览(31)
  • 数据结构--字符串的KMP算法

    朴素模式匹配算法: 一旦发现当前这个子串中某个字符不匹配,就只能转而匹配下一个子串(从头开始) 但我们可以知道: 不匹配的字符之前,一定是和模式串一致的 color{red}不匹配的字符之前,一定是和模式串一致的 不匹配的字符之前,一定是和模式串一致的 我们可以利用

    2024年02月12日
    浏览(49)
  • PTA 7-1 字符串模式匹配(KMP)

    给定一个字符串 text 和一个模式串 pattern,求 pattern 在text 中的出现次数。text 和 pattern 中的字符均为英语大写字母或小写字母。text中不同位置出现的pattern 可重叠。 输入格式: 输入共两行,分别是字符串text 和模式串pattern。 输出格式: 输出一个整数,表示 pattern 在 text 中的出

    2024年02月06日
    浏览(30)
  • Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一个匹配项的下标

    摘要: Leetcode的AC指南 —— 字符串/KMP:28.找出字符串中第一个匹配项的下标 。题目介绍:给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 题目介绍 :给你两

    2024年02月02日
    浏览(48)
  • 【leetcode 力扣刷题】字符串匹配之经典的KMP!!!

    以下是能用KMP求解的算法题,KMP是用于字符串匹配的经典算法【至今没学懂………啊啊啊】 题目链接:28. 找出字符串中第一个匹配项的下标 题目内容: 题意还是很好理解的,要在字符串haystack中查找一个完整的needle,即字符串匹配。 暴力求解就是用 两层循环 :haystack从第

    2024年02月09日
    浏览(32)
  • LeetCode:459. 重复的子字符串 —【2、KMP算法】

    🍎道阻且长,行则将至。🍓 🌻算法,不如说它是一种思考方式🍀 算法专栏: 👉🏻123 题目描述 :给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 来源:力扣(LeetCode) 难度: 简单 提示: 1 = s.length = 104 s 由小写英文字母组成 示例 1: 输入:

    2024年02月04日
    浏览(44)
  • vue中Number方法将字符串转换为数字

    写法: Number(变量名)。例如: 具体情况: 1、如果字符串前面带有0或者其他符号,JS自动忽略 例如: 2、如果字符串是空的或空格,会转换成0 例如: 3、如果是true转换为1,false转换为0 例如: 4、如果是函数、对象、json、undefined,则转换为NAN,表示转不了 5、如果是数组 ①空

    2024年02月06日
    浏览(37)
  • 代码随想录 Leetcode459. 重复的子字符串(KMP算法)

            此解法读者需要了解什么是KMP算法以及KMP算法中next数组的具体含义才能理解         因为在KMP算法的next数组中,next[index]表示 i ndex之前的最大长度的相同前缀后缀值 ,那么要判断整个字符串中是否由重复字串构成,只需要以下两个条件:         1.next[n - 1] !=

    2024年01月19日
    浏览(53)
  • 【数据结构】字符串匹配|BF算法|KMP算法|next数组的优化

    字符串匹配算法是在实际工程中经常遇到的问题,也是各大公司笔试面试的常考题目,本文主要介绍BF算法(最好想到的算法,也最好实现)和KMP算法(最经典的) BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标S的第一个字符与模式串T的第一

    2024年02月04日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包