ACM - 字符串 - 基础(KMP)

news2024/11/15 8:48:09

字符串

  • 一、KMP
    • 1、模板题 HDU1711 Number Sequence
    • 2、求最大匹配数 Ⅰ: HDU 2087 剪花布条(子串不重叠)
    • 3、求最大匹配数 Ⅱ:AcWing 831. KMP字符串(子串可重叠)
    • 4、s2 是不是 s1 的翻转:Leetcode 面试题 01.09. 字符串轮转

一、KMP

1、模板题 HDU1711 Number Sequence

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1711
在这里插入图片描述
题目大意
找出子串第一次出现的位置,找不到输出 - 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

在这里插入图片描述
题目大意
找到子串最大数目,子串间不可重叠。

#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/
在这里插入图片描述
思路
主要是在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/
在这里插入图片描述
思路

这道题目最大的精髓在于将 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 - 翻转

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/510258.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

draw.io二次开发(3)从删删减减开始定制自己的drawio

经过克隆代码、配置IntelliJ/IDEA和Tomcat、以及本地部署&#xff08;详见前几篇&#xff09;之后&#xff0c;终于到了上手改代码的环节了。 首先需要强调的一点是&#xff1a;千万不要去改 *.min.js 文件中的代码&#xff0c;这些文件都是生成的压缩代码&#xff0c;我们一定…

MySQL原理(四):事务

前言 上一篇介绍了 MySQL 的索引&#xff0c;这一篇将介绍事务相关的内容。 在 MySQL 的使用场景中&#xff0c;经常会有一个操作包含多个 SQL 语句&#xff0c;比如转账这个操作&#xff0c;至少包含从甲的账户中扣除金额和给乙的账户中增加金额这两个更新语句。那假如 MySQ…

如何优化VPS服务器性能,提升网站访问速度?

随着互联网的发展&#xff0c;越来越多的企业开始使用VPS服务器来托管其网站。然而&#xff0c;一些企业经常会遇到网站速度慢、响应时间长等问题&#xff0c;这不仅会影响用户的体验&#xff0c;还会导致客户流失。因此&#xff0c;优化VPS服务器的性能&#xff0c;提升网站访…

好程序员:Java培训班包就业靠谱吗?Java培训机构怎么选?

好程序员本身就是培训机构&#xff0c;现在已经10年多了。说句实在话&#xff0c;包就业的机构几乎没有&#xff0c;凡是给你说包就业的机构大多都不靠谱。你还得看机构的培训能力和就业率&#xff0c;其实能否找到工作还得看你自己在培训班学的怎么样了对吧&#xff0c;找工作…

CIAA 网络安全模型 — TLS v1.3 和 HTTPS 协议

目录 文章目录 目录SSL/TLSTLS 1.21. client_hello2. server_hello server_certificate sever_hello_done3. Certificate authentication4. client_key_exchange change_cipher_spec encrypted_handshake_message5. change_cipher_spec encrypted_handshake_message TLS 1…

portraiture3.5.6免费版PS图片磨皮软件

Portraiture是专注于图像后期处理软件研发的 Imagenomic, LLC重头产品之一&#xff0c;在摄影爱好者中极负盛名。Portraiture 可以将繁琐复杂的人像磨皮操作极致简化&#xff0c;不论是普通爱好者或专业后期处理人员&#xff0c;均能一键完成&#xff0c;被称为人像磨皮神器。 …

1. 跨域学习

1. 跨域学习 1.1 什么是跨域 出于浏览器的同源策略限制。同源策略&#xff08;Sameoriginpolicy&#xff09;是一种约定&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;如果缺少了同源策略&#xff0c;则浏览器的正常功能可能都会受到影响。可以说Web是构建在同…

最新全网的ChatGPT让AI回答你的任何问题!国内免费用!!

ChatGPT&#xff0c;最近全网最火爆的顶流话题&#xff0c;不管数码爱好者、新闻媒体&#xff0c;还是投资客&#xff0c;无一不在关注着这一牛掰的人工智能项目 它是由OpenAI实验室推出的一款AI工具&#xff0c;拥有极其智能的对话能力&#xff0c;可以回答任何你提出的问题&…

Vuex-状态管理模式

Vuex Vuex 是一个专为 Vue.js 开发的状态管理模式。主要是是做数据交互&#xff0c;父子组件传值可以很容易办到&#xff0c;但是兄弟组件间传值&#xff08;兄弟组件下又有父子组件&#xff09;&#xff0c;页面多并且一层嵌套一层的传值&#xff0c;非常麻烦&#xff0c;这个…

函数数组的运算

函数数组的运算 一&#xff1a;冒泡运算 类似气泡上涌的动作&#xff0c;会将数据在数组中从小到大或者从大到小不断的向前移动。 基本思想&#xff1a; 冒泡排序的基本思想是对比相邻的两个元素值&#xff0c;如果满足条件就交换元素值&#xff0c;把较小的元素移动到数组前…

D31FBE01EC1NF00PARKER比例方向阀

D31FBE01EC1NF00PARKER比例方向阀是宁波秉圣工业&#xff0c;美国派克比例阀主要具有方向功能&#xff0c;流量功能&#xff0c;压力功能&#xff0c;因此主要有三类&#xff1a;方向阀&#xff0c;流量阀&#xff0c;压力阀&#xff0c;其中方向阀和压力阀直接控制和操作你。被…

一起来!白嫖Amazon DynamoDB!!!

Amazon DynamoDB简介 Amazon DynamoDB是由Amazon Web Services&#xff08;AWS&#xff09;提供的一种快速、灵活、全托管的NoSQL数据库服务&#xff0c;支持文档和键/值数据模型。它具有自动扩展、低延迟、高可靠性、高吞吐量等特点&#xff0c;能够处理从几个字节到几TB的数…

tiechui_lesson08_内存的分配和链表

主要是将链表结构的使用&#xff0c;在内核开发中使用起来比较方便的一种数据结构【LIST_ENTRY】。 一、内存的分配 主要是学习一些基本操作。现在推荐使用的动态分配函数【ExAllocatePoolWithTag】 PVOID tempbuffer ExAllocatePoolWithTag(NonPagedPool, 0x1000, xxaa); …

DJ4-6 层次选路

目录 一、层次选路的基本概念 二、域内路由选择 1、RIP* 2、OSPF 三、域间路由选择 BGP 1、AS 互连 2、AS 域间选路任务 3、示例&#xff1a;在 1d 上设置转发表 4、示例&#xff1a;在多个 AS 中做出选择 5、BGP 会话与通告 6、传播可达信息 7、路径属性和 BGP 路…

马蹄集第四期oj

目录 供水管线 黑客小码哥 逆序 来给单词分类 前k小数&#xff08;进阶&#xff09; 前K小数 线段树 队列安排 一元多项式的加法 快排变形 供水管线 难度&#xff1a;钻石 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;128M 在个城市之间原本要规划修建许多条下水管道…

提高开发团队能力 这4点很重要

组建开发团队&#xff0c;提高开发团队能力的前提是需要选对人&#xff0c;不仅需与专业匹配&#xff0c;与公司文化相匹配&#xff0c;更与管理者相匹配。 而团队能力的提升需要重点关注&#xff1a;流程化&#xff0c;标准化、工具化和持续赋能。尤其通过流程化、标准化和工具…

TIM输入捕获-STM32

TIM输入捕获-STM32 IC(Input Capture) 输入捕获 输入捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存到CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和通用定时器都拥有4个输入捕…

Unity 自建package包流程

目录 1.在工程Asset 同级目录下创建文件夹 名字随便起 2.在文件夹中添加package.json 文件 3.在unity中选中PackageManager 4.打开vs 新建一个项目 5.开始编写代码 6.修改dll路径 7.打个dll 1.在工程Asset 同级目录下创建文件夹 名字随便起 eg: 2.在文件夹中添加package…

《MySQL 必知必会》课程笔记(三)

怎么创建和修改数据表&#xff1f; 创建和修改数据表&#xff0c;是数据存储过程中的重要⼀环。我们不仅需要把表创建出来&#xff0c;还需要正确地设置限定条件&#xff0c;这样才能确保数据的一致性和完整性。同时&#xff0c;表中的数据会随着业务需求的变化而变化&#xf…

docker ngxin

安装docker环境 官方安装 官方安装 Install Docker Engine on CentOS | Docker Documentation sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repoyum install docker-ce docker-ce-cli container…