当前位置: 首页 > news >正文

算法提升之字符串练习-03(KMP)

今天给大家带来的仍是关于字符串类型的算法题目,关于这类题目,大家需要多做练习进行巩固,题型相对固定,但是比较具有思路,希望大家可以好好理解相关部分。

关于KMP算法,通常有两部分组成,第一部分是通过get_next()数组求解next数组,第二部分则是通过KMP求解字符重复。

第一道题:

问题描述

wzy 给了你一个字符串,请你计算一下这个字符串最多是由多少个相同子串拼成的。

注意:原串 abcdabcd,则 abcd 出现两次,则该字符串最多是由两个相同子串拼成的。

输入格式

第一行一个字符串 s 。

输出格式

输出一个数,表示这个字符串最多是由多少个相同子串拼成的。

输入案例:

abcdabcd

输出案例:

2

代码解析:

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char T[N],S[N];
int nex[N];
int n,n1;
void get_nex(int n){nex[0]=nex[1]=0;for(int i=2,j=0;i<=n;i++){while(j&&T[i]!=T[j+1])j=nex[j];if(T[i]==T[j+1])j++;nex[i]=j;}
}
int KMP(int T_length,int S_length){int ans=0;for(int i=1,j=0;i<=T_length;i++){while(j&&T[i]!=S[j+1])j=nex[j];if(T[i]==S[j+1])j++;if(j==S_length)ans++;}if(n%ans==0)return ans;else return 1;
}
int main()
{cin>>T+1;n=strlen(T+1);get_nex(n);n1=n-nex[n];for(int i=1;i<=n1;i++)S[i]=T[i];int b=KMP(n,n1);cout<<b<<endl;return 0;
}

关键点⚠️:
1.最小重复字串长度的求法:

n1 = n - nex[n]
  • 原理
    对于整个字符串T[1..n]nex[n]是其最长前后缀的长度。若T是由某个子串重复组成的,则其最小重复子串的长度为n - nex[n]

    推导:假设T由子串t重复k次组成,那么T的最长前后缀长度nex[n]必然等于n - len(t)(因为前后缀会重叠k-1次)。因此,len(t) = n - nex[n]
  • 示例
    • T = "abcdabcd"n=8):
      nex[8] = 4(最长前后缀是"abcd"),则n1 = 8 - 4 = 4,即最小重复子串长度为 4("abcd")。
    • T = "ababab"n=6):
      nex[6] = 4(最长前后缀是"abab"),则n1 = 6 - 4 = 2,即最小重复子串长度为 2("ab")。
  • 合法性检查
    只有当n能被n1整除时(n % n1 == 0),n1才是有效最小重复子串长度;否则,字符串无法由重复子串组成,答案为 1。

第二题:

问题描述

在古代的文人墨客中,有一种名为“诗歌双联”的创作形式,它将两个诗句拼接在一起,构成具有深意的诗歌。现在,一位名为小桥的学者正在探索这种神秘的创作形式。她发现,通过选取两个不相交的子句,并将它们拼接在一起,有时可以创作出包含特定主题的诗歌。

小桥希望你能帮助她设计一个算法,验证她的想法。给定两个字符串 s 和 t,你需要判断是否可以从字符串 s 中选出两个长度为 k的不相交子字符串,拼接后得到的字符串包含字符串 t。

输入格式

第一行包含三个整数 n,m,k(2≤m≤2⋅k≤n≤102),分别代表字符串 s和字符串 t的长度,以及可选子字符串的长度。

接下来两行分别给出由小写字母组成的字符串 s 和 t。

输出格式

如果存在这样的两个子字符串,使得拼接后得到的字符串包含字符串 t,则输出 "Yes",否则输出 "No"。

输入案例:

7 4 3
baabaab
aaaa

输出案例:

Yes

代码部分:

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
typedef unsigned long long ull;
char s[N],t[N];
const int base=131;
ull bases[N],h1[N],h2[N];
int n,m,k;
ull gethash(int l,int r,ull s[]){return s[r]-s[l-1]*bases[r-l+1];}
int main()
{  cin>>n>>m>>k;cin>>s+1>>t+1;bases[0]=1;for(int i=1;i<=n;i++){bases[i]=bases[i-1]*base;h1[i]=h1[i-1]*base+(int)s[i];if(i<=m)h2[i]=h2[i-1]*base+(int)t[i];}for(int i=1;i+m-1<=n;i++)           //特判一下拆分t数组,一边把t数组全选的情况{if(gethash(i,i+m-1,h1)==gethash(1,m,h2)){cout<<"Yes"<<'\n';return 0;}}for(int i=1;i<m;i++)     //拆分t数组,选择两边有用的选的字符串长度,确保算哈希值的时候区间合法{if(i>k||m-i>k)continue;int l=k,r=n-k+1;while(l<r)           //确保没有重合,左边选择的字符放在前面{if(gethash(l-i+1,l,h1)==gethash(1,i,h2)&&gethash(r,r+m-i-1,h1)==gethash(i+1,m,h2)){cout<<"Yes"<<'\n';return 0;}if(gethash(l-i+1,l,h1)!=gethash(1,i,h2))l++;if(gethash(r,r+m-i-1,h1)!=gethash(i+1,m,h2))r--;}}cout<<"No"<<'\n';return 0;
}

好了今天的分享就到这里了,希望大家可以多加巩固。

http://www.dtcms.com/a/285909.html

相关文章:

  • docker,防火墙关闭后,未重启docker,导致端口映射失败
  • 【51】MFC入门到精通——MFC串口助手(一)---初级版(串口设置、初始化、打开/关闭、状态显示),附源码
  • Java异步日志系统性能优化实践指南:基于Log4j2异步Appender与Disruptor
  • 鸿蒙实现一次上传多张图片
  • 物流3D工业相机:解锁自动化物流新纪元
  • 第三章-提示词-初级:一文带你入门提示词工程,开启AI高效交互之旅(11/36)
  • [Python] -实用技巧8-解锁 Python 中的 lambda 表达式用法
  • GISBox切片器技术解析:RVT模型到3DTiles瓦片的高性能转换方案
  • 内存数据库的持久化与恢复策略:数据安全性与重启速度的平衡点
  • QT窗口(3)-状态栏
  • 菱形继承 虚继承
  • vue-router
  • 前端篇——番外篇 Bootstrap框架
  • 【密码学】1. 引言
  • c++继承详解
  • 【物联网】基于树莓派的物联网开发【12】——树莓派硬件GPIO模块原理知识
  • 模式结构-微服务架构设计模式
  • 【PTA数据结构 | C语言版】二叉堆的快速建堆操作
  • 一文讲清楚React性能优化
  • mysql 性能优化之Explain讲解
  • RHEL/CentOS 的系统安装程序界面介绍
  • 周志华《机器学习导论》第9章 聚类
  • 分布式面试点
  • 算法-动态规划
  • MyBatis缓存实战指南:一级与二级缓存的深度解析与性能优化
  • 分布式短剧平台核心技术解析:CDN优化、AI推荐与多语言支付集成
  • 在 ASP.NET Core 和 JavaScript 中配置 WebSocket
  • Jfinal+SQLite处理 sqlite数据库执行FIND_IN_SET报错
  • .NET 8 Release Candidate 1 (RC1)现已发布,包括许多针对ASP.NET Core的重要改进!
  • 从复合变量到分组分析:piecewiseSEM 解析生态系统多因子交互作用