KMP例题

2023-11-06

KMP算法:实现两个字符串的匹配。
KMP讲解

//KMP模板
#include<bits/stdc++.h>
using namespace std;

void get_next(string t, int* next){
	int i=0;
	int j=-1;
	next[0]=-1;
	while(i<t.length()){
		if(j==-1||t[i]==t[j]){
			i++,j++;
			next[i]=j;
		}
		else{
			j=next[j];
		}
	}
}

int kmp(string s, string t){
	int next[t.length()+5];
	get_next(t, next);
	int i=0;
	int j=0;
	while(i<s.length()&&j<t.length()){
		if(j==0||s[i]==t[j]){
			i++,j++;
		}
		else{
			j=next[j];
		}
	}
	
	if(i==s.length()){
		return -1;
	} 
	if(j==t.length()){
		return i-t.length()+1;
	}
}

int main(){
	string a, b;
	a="abcde";
	b="cd";
	cout<<kmp(a, b);
	
	return 0;
} 

推荐学习KMP链接

例一:子串

牛客题目链接
给出一个正整数n,我们把1…n在k进制下的表示连起来记为s(n,k),例如s(16,16)=123456789ABCDEF10, s(5,2)=11011100101。现在对于给定的n和字符串t,我们想知道是否存在一个k(2 ≤ k ≤ 16),使得t是s(n,k)的子串。
输入描述:
第一行一个整数n(1 ≤ n ≤ 50,000)。
第二行一个字符串t(长度 ≤ 1,000,000)
输出描述:
“yes"表示存在满足条件的k,否则输出"no”
示例1
输入
8
01112
输出
yes


这道题直接套KMP模板就行,没有太多拐弯抹角的东西。

#include<bits/stdc++.h>
using namespace std;
char jz[18]="0123456789ABCDEF";
string t, s="";

void zh(int n, int k){
	string ss;
	while(n>0){
		if(n%k!=0){
			ss+=jz[n%k];
		}
		else ss+=jz[0];
		n/=k;
	}
	reverse(ss.begin(), ss.end());
	s += ss;
}

void get_next(string t, int*next){
	int i=0;
	int j=-1;
	next[0]=-1;
	while(i<=t.length()){
		if(t[i]==t[j]||j==-1){
			j++, i++;
			next[i]=j;
		}
		else{
			j=next[j];
		}
	}
}

bool kmp(string s, string t){
	int next[t.length()+5];
	get_next(t, next);
	int i=0;
	int j=0;
	while(j<t.length() && i<s.length()){
		if(t[j]==s[i]||j==0){
			j++, i++;
		}
		else{
			j = next[j];
		}
	}
	if(j==t.length()){
		return true;
	}
	return false;
}

int main()
{
	int N;
	cin>>N>>t;

	for(int k=2; k<=16; k++){
		s="";
		for(int n=1; n<=N; n++){
			zh(n, k);
		}
//		cout<<s<<endl;
		if(kmp(s, t)){
			cout<<"yes";
			return 0;
		}
	}
	cout<<"no";
	
	return 0;
} 

例二:Youhane Assembler

牛客题目链接
题意:输入多个字符串,挑选两个字符串s1,s2。
判断s1的后缀字母与s2的前缀字母有多少个字符能匹配。
eg:s1=“ABCDE” s2=“CDEFG”
ps:它们能匹配的字符有3个为"CDE"。
eg: s1=“CDEFG” s2=“ABCDE”
ps:它们能匹配的字符有0个,因为s2字符串中没有G。


运用KMP特性

在KMP里我们了解到,next数组能够将一个字符串前后缀进行匹配,从而达到避免字符串匹配的时候重复判断的效果。
在题目中,我们可以利用next数组匹配字符串前后缀的功能来实现s1与s2的匹配。

解题分析

①、将s1与s2结合为一个字符串s
s=s2+"#"+s1
(ps:s2要前缀,s1要后缀,在中间加上"#"防止s2与s1“越界匹配”)
②、判断字符串s的前缀与后缀有ans个字符能匹配成功。
ans = next[s.length()]

#include<bits/stdc++.h>
using namespace std;
string str[300005];
void get_next(string s, int * next){
	int i=0;
	int j=-1;
	next[0]=-1;
	while(i<s.length()){
		if(s[i]==s[j]||j==-1){
			i++, j++;
			next[i]=j;
		}
		else{
			j = next[j];
		}
	}
}

int main()
{
	int n;
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>str[i];
	int m;
	cin>>m;
	for(int i=1; i<=m; i++){
		int q1, q2;
		cin>>q1>>q2;
		string s = str[q2]+"#"+str[q1];
		int len=s.length();
		if(q1==q2){
			cout<<str[q1].length()<<endl;
		}
		else{
			int next[s.length()+5];
			get_next(s, next);
			cout<<next[len]<<endl;
		}
	}
	return 0;
}

例三:[水] 悠悠碧波

牛客测试平台
题目描述
帕秋莉掌握了一种水属性魔法
这种魔法可以净化黑暗
帕秋莉发现对于一个黑暗的咒语s,可以使用这个水元素魔法净化它,净化的咒语是一个最长的字符串t,t满足以下条件:
它是s的前缀
它是s的后缀
除前缀和后缀外,它还在s中出现过至少一次
既然你都学会了,那么净化的工作就交给你了!

输入描述:
一行字符串 s 代表黑暗咒语
输出描述:
一个字符串 t 表示满足条件的最长净化咒语

示例1
输入
tqrwantoacthisproblembutqristooweaktodoitqr
输出
tqr

备注:
对于60%的数据,s长度≤100
对于100%的数据,s长度≤100,000
保证存在可行的净化咒语


注意:前后缀不可重叠

不能直接利用 next 函数进行前后缀是否相等的判断,这里我用双指针(l,r)的方式进行前后缀是否相等的判断。
l : 指向前缀的结尾字符下标
r : 指向后缀的开头字符下标

解题步骤

初始化:l =0, r=s.length()-1

1、确定 t 串条件
限制条件:
排除大部分多余情况
①、前缀与后缀长度相等
②、前缀的结尾字符 == s 的结尾字符(s[l] == s[s.length()-1])
③、后缀的开头字符 == s 的开头字符(s[r] == s[0])

最终确定
①、前缀与后缀完全相等
②、利用 kmp 判断字符串 s 在下标为 l+1 ~ r-1 的范围内有无与前缀相同的串

2、若满足1内所有条件则将下标 l 保存

3、试探有没有更大的字符串符合条件

4、若 l>=r ,输出字符串 s 的前缀下标为 0 ~ l ,结束程序。否则将 l++,回到步骤1


以上解题步骤还有一些优化的空间,例如 l < r可以改为 l < s.length()/3,有兴趣的朋友可以接着优化。

#include<bits/stdc++.h>
using namespace std;
string s;
void get_next(string T, int*next){
   int i=0, j=-1;
   next[0]=-1;
   while(i<T.length()){
       if(T[i]==T[j]||j==-1){
           j++;
           i++;
           next[i]=j;
       }
       else
           j = next[j];
   }
   return ;
}

bool kmp(int begin, int end, string s, string T){
   int next[100010];
   get_next(T, next);
   int i=begin, j=0;
   while(i<=end&&j<T.length()){
       if(s[i]==T[j]||j==0){
           i++,j++;
       }
       else{
           j = next[j];
       }
        
   }
   if(j==T.length()) return true;
   else return false;
}

int main(){
   cin>>s;
   int l=0, r=s.length()-1, ans=0, l_len, r_len;
   char L=s[l], R=s[r];
   while(L!=s[r]) r--;
   while(R!=s[l]) l++;
   
   while(l<r){
   	l_len = l+1;
   	r_len = s.length() - r;
    while(l_len!=r_len){
          if(L!=s[r] || R!=s[l]){
              while(L!=s[r]&&l<r) r--; //将前缀的开头字母与后缀的开头字母配对
              while(R!=s[l]&&l<r) l++; //将后缀的结尾字母与前缀的结尾字母配对
          }
          else if(l_len>r_len){
              r--;
          }
          else{
              l++;
          }
          l_len = l+1;
       	  r_len = s.length() - r;
       }
       string T = s.substr(0, l+1), t = s.substr(r);
        
       //保证前后缀相同,同时在中间找与前后缀相同的串
       if(T==t&&kmp(l+1, r-1, s, T))
           ans = l+1;
        
       //试探有没有更长字符串
       l++, r--;
       while(R!=s[l]) l++;
       while(L!=s[r]) r--;
   }
   cout<<s.substr(0, ans);
    
   return 0;
}

希望将自己的学习经验分享给有需要的人。
我是小郑,一个不怎么会的小白

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

KMP例题 的相关文章

  • Bridge:桥接模式

    将抽象部分与它的实现分离 使他们都可以独立地变化 抽象与实现的分离方法 是借助耦合 对于一个派生类而言 其从基类继承了抽象函数 并对抽象函数进行实现 这是常规的抽象与实现耦合的情况 而 若将函数实现的功能代码抽出 放到一个特定的实现类里 并

随机推荐

  • 设计模式(适配器模式)

    这里写目录标题 一 应用 1 1 概念 1 2 应用场景 二 实现 2 1 Python实现 2 2 Java实现 2 3 Golang实现 一 应用 1 1 概念 适配器是一种结构化的设计模式 主要是为了让不兼容的对象能够相互兼容 1 2
  • shell脚本——循环语句、sed、函数、数组、免交互expect

    目录 循环语句 for while 与 until sed 基本用法 sed脚本格式 函数 注意事项 定义函数和调用函数 脚本中函数的位置 查看函数 删除函数 函数返回值 函数的传参操作 使用函数文件 递归函数 数组 声明数组 数组切片 免
  • 记录 BL-604 环境配置

    与两个朋友组队参加个比赛 第一次正经的参加比赛 弥补之前一些遗憾吧 随便记录一下 下载博流的开发包 https gitee com bouffalolab bl mcu sdk 注册平头哥 https occ t head cn auth
  • NandFlash介绍、操作流程分析以及S5PV210的NandFlash控制器介绍

    1 NandFlash的型号与命名 注 本文以S5PV210芯片和K9F2G08芯片做分析 1 Nand的型号命名都有含义 拿K9F2G08来示例分析一下 K9F表示是三星公司的NandFlash系列 2G表示Nand的大小是2Gbit 2
  • Tomcat 各安装包选择及使用情景。

    本文参考 Apache Tomcat 8 5 51 官方 README 文件 当我们进入 Tomcat 主页下载 Tomcat 时 会看到各种安装包的选择 Binary Distributions 二进制发行包 Core zip pgp s
  • QT/C++ 多线程时,工作界面的样式频繁改变导致程序奔溃的问题

    QT C 多线程时 工作界面的样式频繁改变导致程序奔溃的问题 一 错误现象与原因 最近在学习QT 遇到了一点问题 是关于工作线程与UI线程的 其主要问题为 我的工作线程是一个死循环 当我点击按钮进入工作线程 我的工作线程用emit发送一个信
  • IDEA使用JUnit时@Test无效以及无法导入org.junit包的一系列问题

    先找到idea的安装位置 进入lib文件夹 然后打开idea File gt Project Structure 选择Project Settings中的Libraries 点击如图 号 然后添加以下两个包 点击OK 添加成功就可以了 ht
  • 3.java 基础if语句测评题-答案

    知识点 java 基础if语句测评题 答案 题目1 训练 李雷想买一个价值7988元的新手机 她的旧手机在二手市场能卖1500元 而手机专卖店推出以旧换新的优惠 把她的旧手机交给店家 新手机就能够打8折优惠 为了更省钱 李雷要不要以旧换新
  • SQL-更新和删除数据

    如何使用UPDATE和DELETE语句进一步操作表数据 1 更新数据 更新 修改 表中的数据 使用UPDATE语句 更新表中的特定行 更新表中的所有行 注 不要省略WHERE子句 在使用UPDATE时一定要细心 因为稍微不注意 就会更新表中
  • ArcGIS教程:面积制表

    摘要 计算两个数据集之间交叉制表的区域并输出表 插图 使用方法 区域定义为输入中具有同样值的全部区 各区无需相连 栅格和要素数据集都可用于区域输入 假设区域输入和类输入均为具有同样分辨率的栅格 则可直接使用它们 假设分辨率不同 则可先应用内
  • AT指令(中文详解版)

    AT命令最常见的应用场景 1 智能手机 一般智能手机都是一个主芯片控制一个通信模块 这个通信模块就是一个完整的 简单的手机 包括手机应该有的射频 基带等部分 还有GSM协议栈 完全可以独立打电话 发短信 用GPRS上网等 主芯片实现复杂的应
  • 【GD32篇】新建KEIL工程

    以GD32f103C8T6芯片为例 一 下载MDK5 软件包 下载地址 https www keil com dd2 pack 1 选择工程所需的软件包 2 打开软件包 安装在KEIL5同路径下 3 安装成功后打开keil软件 可查看到自己
  • 经典Hive-SQL面试题及答案

    目录 第一题 求分区累加值 第二题 UV和每个店铺访问量top3信息 Hive sql解答 第一题 求分区累加值 我们有如下的用户访问数据 userId visitDate visitCount u01 2017 1 21 5 u02 20
  • 单片机C语言基础知识-指针篇

    引言 指针是变量在计算机或单片机内所占有的存储区域的地址 C51语言中广泛使用的指针概念是从C语言中继承下来的 利用指针变量不但可以操作各种基本的数据类型 而且能使C51语言像汇编语言一样 具有处理单片机内存地址的能力 地址 指针 指针变量
  • Paramiko远程操作Linux服务器

    在日常工作中我们经常会跟Linux打交道 对于测试同学来说 使用Linux的场景还是比较多的 比如 搭建测试环境 查看日志信息 修改配置文件 监控服务资源等 本篇将介绍一个Python的第三方库Paramiko 使用Paramiko 我们可
  • ChatGPT学python——制作自己的AI模型(一)初步了解

    前言 作者主页 雪碧有白泡泡 个人网站 雪碧的个人网站 推荐专栏 java一站式服务 前端炫酷代码分享 uniapp 从构建到提升 从0到英雄 vue成神之路 解决算法 一个专栏就够了 架构咱们从0说 数据流通的精妙之道 文章目录 前言 引
  • 离线环境下手动安装python环境的依赖包

    在写完python代码之后 想要部署到服务器上 但由于服务器无法连接外网 对应的服务器上也没有代码中用到的包 怎么进行手动安装 正是一件麻烦的事情 现在主要针对这样的情况介绍几种依赖包的手动安装 这里主要介绍flask和jieba的安装 关
  • opencv获取多个摄像头名字和编号

    https blog csdn net hyqwmxsh article details 74479694
  • 房地产不同视角

    author skate time 2012 08 14 房地产不同视角 房地产 你为啥看不懂 一 看现象与看本质 http blog sina com cn s blog 77479d2301015cpk html 房地产 你为啥看不懂
  • KMP例题

    KMP算法 实现两个字符串的匹配 KMP讲解 KMP模板 include