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

怎么看网站有没有被k小程序论坛

怎么看网站有没有被k,小程序论坛,做网站的接私活犯法吗,网件路由器appKMP 算法是一种字符串匹配算法。字符串匹配算法的目标是:在字符串 s 中找到与模式串 p 相等的子串,输出其位置。例如:s “abcdef”,p “cdef”,p 在 s 中的位置是 2(从 0 开始计数)。 容易想到…

KMP 算法是一种字符串匹配算法。字符串匹配算法的目标是:在字符串 s 中找到与模式串 p 相等的子串,输出其位置。例如:s = “abcdef”,p = “cdef”,p 在 s 中的位置是 2(从 0 开始计数)。

在这里插入图片描述
容易想到的方式就是暴力算法。

    int findString(string s, string p) {int n = s.size(), m = p.size();int i, j;for (i = 0; i < n - m + 1; i++) {for (j = 0; j < m; j++) {if (s[i] == s[j]) continue;break;}if (j == m) return i;}return -1;}

暴力算法的最坏情况下,时间复杂度是 O ( n m ) O(nm) O(nm)。而本文尝试要讲明白的 kmp 算法,他的摊还时间复杂度是 O ( n ) O(n) O(n) 的。
kmp 算法执行速度要快不少,但是也是有代价的:也就是出了名的难理解。但我认为,只要 提纲挈领的找到 kmp 算法的主干,那还是比较好理解的,也就 2 分钟的事吧。算法实现上会有一些坑,这才是最难的地方,需要将里面的思路捋顺,但花些时间总能搞出来。那我们就开始吧。

从直觉开始

假设有这样一个样例:s = “bacbababababcbab”,p = “ababaca”。算法运行到如下位置时,匹配错误了。
在这里插入图片描述
暴力算法会移进 1 字符,然后重新从 s 的 5 号字符和 p 的 0 号字符开始匹配。相当于 s 的索引回退到 5,p 的索引回退到 0。
在这里插入图片描述
而 kmp 算法就比较聪明一些。既然 p 字符串的 0 到 4 号元素都匹配成功了,我们何不利用这个信息,多向前移动几个字符呢?怎么做呢? kmp 算法的思想如下:到目前位置,已经成功匹配了 p 的前缀中 “ababa” 这个字符串。然后我们同时考虑它的 前缀 和 后缀,会发现
在这里插入图片描述
它的前三个字符和后三个字符是完全一样的。所以我们完全可以向下图一样,从 s 的 9 号 字符和 p 的 3 号字符开始匹配,相当于 s 的索引没有回退,p 的索引回退到 3。这可比暴力匹配回退的少多了,因此也就快多了。
在这里插入图片描述
至此 kmp 算法的思想就讲完了。上述思想,如果不考虑如何实现的话,可能最多 2 分钟就可以理解。
但是想要实现它却又不知该怎么下手,那我们就一点一点的拆解它。

next 数组引入

next 数组,往往又叫前缀函数。我们不整那么高深的东西,就为了解决一个问题:p 的索引该回退到哪? 根据上面的分析,s 的索引是没有回退的,那么 p 的索引该回退到哪里呢?这个问题需要再精确一些:如果 p 在 索引 i 的位置匹配失败了,那么 p 的索引该回退到哪里?这就是 next 数组的作用:索引应该回退到 next[i] 的位置。
为了不使代码复杂化,我们先假设,如果已经得到了 next 数组,算法框架是什么样的呢?

  • 版本1:
    int findString(string s, string p) {int n = s.size(), m = p.size();int i, j = 0;for (i = 0; i < n;) {if (s[i] == p[j]) { // 如果相等,i 和 j 都进 1i++, j++;} else { // 如果不相等,i 保持不变,j 变为 next[j]j = next[j];}// 如果 j == m 表示 s 在 i 处匹配完成了,返回 i - m;if (j == m) return i - m;}return -1;}

根据版本一的注释,看起来好像没什么问题,但不幸的是,它有 bug。j = next[j] 这一行没有处理边界情况:即当s[i] 不等于 s[j],并且,当 j == 0 时,意味着 0 号位置也匹配失败了,这时候 next[j] 应该等于多少呢?答案是:还是 0。为什么呢?即使 0 号位置匹配失败了,下一次应该是要把 s 的索引加 1,而 p 的索引依旧是 0 才对。于是有了下面的代码版本。
plus. 有一些别的 kmp 算法版本 定义为 -1。实际上是把整个 next 数组做了一次变换,只要改一下 next 数组的定义即可。我们学会一个就好了。

版本2.1

    int findString(string s, string p) {int n = s.size(), m = p.size();int i, j = 0, flag = 0;for (i = 0; i < n;) {if (s[i] == p[j]) { // 如果相等,i 和 j 都进 1i++, j++;} else { // 如果不相等,i 保持不变,j 变为 next[j]j = next[j];if (flag == 1) {flag = 0;i++;} else if (j == 0) flag = 1;}// 如果 j == m 表示 s 在 i 处匹配完成了,返回 i - m + 1;if (j == m) return i - m;}return -1;}

版本2.1是一个正确的版本,但是不够优雅。作为一个程序员,要有一定的审美,版本 2.1 本质上是用单层循环模拟了多层循环,如果能够拆出来,就更好了。
版本2.2

		int n = s.size(), m = p.size();int i, j = 0;for (i = 0; i < n; i++) {// 如果不相等,i 保持不变,j 变为 next[j]while (j != 0 && s[i] != p[j]) {j = next[j];}if (s[i] == p[j]) { // 如果相等,j 进 1j++;}// 如果 j == m 表示 s 在 i 处匹配完成了,返回 i - m + 1;if (j == m) return i - m + 1;}return -1;}

嗯,版本2.2 就优雅许多了。

next 数组生成

那么 next 数组该如何生成呢?
在这里插入图片描述
对照这幅图,当 p 的 5 号索引匹配失败是,j 应该跳转到 3 号。可以观察到,next[i] 表示 [0, i - 1] 区间表示的字符串 p i p_i pi 中 重叠的前缀与后缀的最长值 k,并且 k 要小于 p i p_i pi 的长度,因为自己等于自己可不算。
所以算法如下

     vector<int> next(m, 0);for (int i = 2; i < m; i++) { // 前两个数字默认为 0int t = next[i - 1]; // 前面的前面的那个区间有最长多少个重叠的前后缀// 前面的区间末尾 和 前面的前面的区间的末尾如果不相等就一直 next// 这点和匹配算法很像while (t != 0 && p[i - 1] != p[t]) { t = next[t];}next[i] = t;if (p[i - 1] == p[t]) next[i] = t + 1; //如果相等就 +1}

合成如下

    int strStr(string s, string p) {int n = s.size(), m = p.size();// 求 next 数组vector<int> next(m, 0);for (int i = 2; i < m; i++) {int t = next[i - 1];while (p[i - 1] != p[t] && t != 0) t = next[t];if (p[i - 1] == p[t]) t++;next[i] = t;}// 匹配int j = 0;for (int i = 0; i < n; i++) {while (s[i] != p[j] && j != 0) j = next[j];if (s[i] == p[j]) j++;if (j == m) return i - m + 1;}return -1;}

总结

kmp 算法思想就是使用已匹配的前缀字符串,从中抽取出前后缀的重叠部分信息,用以减少字符串匹配中的回退,从而达到加速的作用。其实现有两个坑,一个是next 数组含义的准确定义(我的定义应该和书上不一样),第二个坑就是使用内循环来多次使用 next 数组跳转。其中第二个坑相信大家自己写都能意识到,第一个坑才是决定你能不能写出来的关键因素。我的实现可能不是最好的,但是希望能够好懂一点。

kmp 算法已将前缀信息使用到了极致,还有一些别的字符串比较算法要比 kmp 容易一些,比如 sunday 算法等。还有一些算法可能比 kmp 还要复杂一些,使用到了后缀信息,例如:bm 算法。还有 一个 RK 算法使用哈希字符串的方式,简单易写。这些算法有机会再说吧。

http://www.yayakq.cn/news/686270/

相关文章:

  • 设计专业所需网站wordpress相册居中
  • 衡水网站建设公司联系电话网页版微信小程序
  • 长沙有哪些网站建设公司好wordpress菜单不兼容
  • 做阿里巴巴网站口碑包装设计网站是什么样子的
  • 华为手机官方网站登录软文怎么优化网站
  • 开办时 网站建设费 科目百度秒收录的网站
  • 网站开发项目总结报告wordpress如何修改语言设置
  • php个人网站怎么做怎么申请 免费网站
  • 网站建设的原因有什么山西省吕梁市邮政编码
  • 重庆有效的网站推广专业企业网站建设哪家服务好
  • 做本地房产网站台州网站制作开发
  • 网站建设需要多少钱费用深圳移动网站建设公司
  • 动易网站开发的主要技术美橙互联网站建设
  • 网站运行维护方案高碑店建设局网站
  • 什么网站专做衣服龙口网站建设公司报价
  • 网站更改指定字段杭州棋牌软件开发公司
  • 社交模板网站建设东营做网站m0536
  • 房产网站怎么做400电话网站备案各种问题汇总
  • wordpress 通知插件怎么做网站关键词优化
  • 天津医疗行业网站建设dw做的网站有什么缺陷
  • 甘孜州住房城乡建设局网站自适应网站建设软件
  • 哪些网站设计好wordpress图片表单插件
  • 网站建站加盟昆山网站建设义搏
  • 国内哪个网站用wordpress网站存储空间大小
  • 帝国cms网站公告怎么做抖音seo优化公司
  • 如何诊断网站网站素材资源
  • 一个企业网站的建设流程最新项目网
  • wordpress导航类主题广东宣布即时优化调整
  • 昆明优化网站公司永久免费国外vps无需信用卡
  • 怎么知道网站的空间服务商厦门百度搜索网站排名