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

音平商城谁做的网站做的好的茶叶网站好

音平商城谁做的网站,做的好的茶叶网站好,创建国际网站,龙游网站建设的公司前缀函数的运用 KMP在字符串中查找子串,本质是对前缀函数的运用。例题1 给定一个文本串 ttt,和一个模板串 sss,找出 sss 在 ttt 中出现的所有位置。 题解 构造一个字符串 hs#ths\#ths#t,hhh 由 三个部分 组成,第一个部…

前缀函数的运用

KMP

在字符串中查找子串,本质是对前缀函数的运用。

例题1

给定一个文本串 ttt,和一个模板串 sss,找出 sssttt 中出现的所有位置。

题解

构造一个字符串 h=s+#+th=s+\#+th=s+#+thhh三个部分 组成,第一个部分是模板串 sss,第二个部分是一个在 sssttt 中都不会出现 的字符 #\##,第三部分是文本串 ttt

可以对 hhh 跑一遍前缀函数,然后所有前缀函数大小为 s.size() 的位置就是 sss 完整在文本串中出现且 sss最后一个字符 所处的位置。

由于 hhh 有偏移,所以得到的位置应该减去 2*s.size()-1

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define INF 1e18
const int N = 1e6 + 7;struct PrifixFunction {int n;string s;vector <int> p;PrifixFunction (int _n, string _s) : s(_s), n(_n), p(_n + 1){}void getPrifixFunction () {p[0] = 0;for (int i = 1; i < n; i++) {int j = p[i - 1];while (j && s[j] != s[i]) {j = p[j - 1];}if (s[j] == s[i]) j ++;p[i] = j;}}
};void solve () {string t, s;cin >> t >> s;string h = s + "#" + t;PrifixFunction pp(h.size(), h);pp.getPrifixFunction();vector <int> ans;for (int i = 0; i < h.size(); i++) {if (pp.p[i] == s.size()) ans.push_back(i - 2*s.size() + 1);}for (auto i : ans) cout << i << endl;
}
signed main() {solve();
}

字符串的周期

对于字符串 sss,若 sss 存在周期 T(1≤T≤∣s∣)T(1\le T\le |s|)T(1Ts),则对于所有的 i∈[0,∣s∣−T−1]i\in[0,|s|-T-1]i[0,sT1] 都有 s[i]=s[i+T]s[i]=s[i+T]s[i]=s[i+T]

不难发现,若存在一个子串 rrr,既是 sss 的一个 真前缀,又是 sss 的一个 真后缀,那么 sss 一定有周期 t=∣s∣−∣r∣t= |s|-|r|t=sr

因为 i+t≤∣s∣−1i+t\le|s|-1i+ts1,当 iii最大值 的时候,该不等式取等号,而 iii 至多只能到 ∣r∣−1|r|-1r1,所以 t=∣s∣−∣r∣t=|s|-|r|t=sr

又因为这样的 rrr 的长度最大不超过 π(∣s∣−1)\pi(|s|-1)π(s1),所以我们就说 sss 的最小周期是 π(∣s∣−1)\pi(|s|-1)π(s1)

统计每个前缀的出现次数

例题1

给定一个长度为 nnn 的字符串 sss,统计 sss 的每个前缀在 sss 中的出现次数。

题解

若存在一个子串 rrr,既是 sss 的一个 真前缀,又是 sss 的一个 真后缀,那么我们就称 rrrsss 的一个 borderborderborder

xxxsss 的真前缀,如果 xxxsss 中出现了一次以上,那么必然能截取出一个子串 ttt,使得 xxxtttborderborderborder

所以我们对于每个子串 s[0...i]s[0...i]s[0...i],求出其所有的 borderborderborder 并进行累加即可。

如果一个长度为 lenlenlenborderborderborder 出现了 xxx 次,那么不管子串多长 p[len−1]p[len-1]p[len1] 都是仅次于 lenlenlenborderborderborder

所以一个长度为 lenlenlenborderborderborder 的出现次数,也代表了一部分 p[len−1]p[len-1]p[len1] 的贡献。

我们先记录每个子串最大长度的 borderborderborder 出现次数,然后倒序累加就行了。

随后别忘记加上前缀自身出现的一次。

vector<int> p(n);
vector<int> cnt(n + 1, 0); // cnt[i] 表示长度为 i 的前缀出现次数// 1. 计算前缀函数
for (int i = 1; i < n; i++) {int j = p[i - 1];while (j && s[j] != s[i]) j = p[j - 1];if (s[j] == s[i]) j++;p[i] = j;
}// 2. 统计每个长度的出现次数(不含自己作为前缀的那一次)
for (int i = 0; i < n; i++) cnt[p[i]]++;// 3. 把出现次数沿着 border 链上传递
for (int len = n; len > 0; len--) {cnt[p[len - 1]] += cnt[len];
}// 4. 每个前缀本身出现一次
for (int i = 1; i <= n; i++) cnt[i]++;

例题2

sss 中的每个前缀在 ttt 中出现的次数。

题解

构造一个字符串 h=s+#+th=s+\#+th=s+#+t,其中 #\## 是不在 sssttt 中存在的字符。

接下来我们就用例题 111 的求法,求出 hhh 的每个前缀在自身中出现的次数。

然后我们再对 sss 这个字符串单独计算一遍其每个前缀在自身中出现的次数。

将两个数组相减即可。

当我们需要用的时候,将它们封装到结构体里就行了。

sss 中本质不同子串的数量

例题1

sss 中本质不同子串的数量。

题解

考虑迭代的做法,设 kkk 是当前的 sss 中本质不同的子串的数量,若在 sss 后面增加一个字符 ccc,记作 s1s_1s1

那么最多增加 ∣s∣+1|s|+1s+1 个本质不同的子串,且这些子串都是以 ccc 结尾的。

此时我们可以将当前字符串 s1s_1s1 反转,设为 s1Ts_{1}^{T}s1T,对其跑一遍前缀函数。

然后求出 s1Ts_1^{T}s1T 的每个前缀在自身中出现多少次,那些只出现一次的就是增加的本质不同的子串。

求出 s1Ts_1^{T}s1T 中只出现一次的前缀,就相当于找出最大的 π\piπ 值,最大的 π\piπ 值表示前缀的字符串到哪里开始不重复出现。

所以只出现一次的前缀数量就相当于 ∣s∣+1−πmax|s|+1-\pi_{max}s+1πmax

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

相关文章:

  • 【算法】队列 + 宽度优先搜索
  • 机器学习周报十八
  • C# 参数详解:从基础传参到高级应用
  • 棠下网站建设jsp如何进行购物网站开发
  • 惠州做网站公司部门门户网站建设请示
  • 分析一下Xshell效率实战——SSH管理秘籍
  • 怎么做卖橘子的网站做网站编辑我能力得到提升
  • 支付通道网站怎么做网页设计代码计算器
  • 做价值投资有哪些网站企业集团网站建设与运营
  • 大型网站开发团队分析杭州高端网站建设开发的区别
  • C++深度解析:从核心特性到现代编程实践
  • 电商网站建设优缺点网站 微信 app
  • dw网站开发环境百度大搜
  • 有什么发布做投标报价的网站wordpress 首页添加图片不显示
  • 杭州协会网站建设做电子书网站
  • 163网站源码做优化很好的网站
  • JdbcTemplate(会用)
  • LangGraph 源码学习总结 2-图计算模型
  • 网站的建设技术有哪些内容在湖南建设人力资源网站
  • 网站被k的怎么办枫林seo工具
  • 网站布局分类商城网站的功能
  • 足球个人网站模板公司商标注册怎么弄
  • vps做网站 推广wordpress是不是很慢
  • 建设部网站哪里可以报名考监理员怎么做网站平台教程
  • 网站做相片页游网站建设
  • 网站制作泉州公司做系统之前的网站
  • 数据驱动+AI:重塑安全应急与网络安全的技术实践与方法论
  • 西部网站域名出售海口网站制作设计
  • 目前网站开发的主流语言是什么wordpress公司展示网站模板
  • 聊城做网站公司聊城博达网站设计公司哪家好