起因

昨天看了阮一峰老师的一篇博客《字符串匹配的KMP算法》,讲的非常棒。这篇文章也是解决了:

有一个字符串"BBC ABCDAB ABCDABCDABDE",里面是否包含另一个字符串"ABCDABD"?

后来发现,其实这不是就PHP自带函数strpos的功能吗?于是突发奇想,自己写个类,实现一下这个算法。

代码

<?php

class KMP
{
public $haystack;
public $needle;
private $_haystackLen;
private $_needleLen;
private $_matchTable;
private $_isMatch; //构造函数
function __construct($haystack,$needle)
{
$this->haystack = $haystack;
$this->needle = $needle;
} //初始化一些参数
private function init(){
$this->_haystackLen = $this->getLen($this->haystack);
$this->_needleLen = $this->getLen($this->needle);
$this->_matchTable = $this->getMatchTable();
$this->_isMatch = false; } //类似strpos函数功能
public function strpos()
{
$this->init(); //haystack
$haystackIdx = $matchNum = 0;
while ($haystackIdx <= $this->_haystackLen - $this->_needleLen){
//needle
$needIdx = 0;
for (; $needIdx < $this->_needleLen; $needIdx++){
if (strcmp($this->haystack[$haystackIdx],$this->needle[$needIdx]) <> 0){
if ($matchNum > 0){
$lastMatchValue = $this->getLastMatchValue($needIdx-1);
$haystackIdx += $this->getStep($matchNum,$lastMatchValue);
$matchNum = 0;
} else {
$haystackIdx++;
}
break;
} else {
$haystackIdx++;
$matchNum++;
if ($matchNum == $this->_needleLen){
$this->_isMatch = true;
break;
}
}
}
if($this->_isMatch == true){
break;
}
}
return $this->_isMatch ? $haystackIdx - $this->_needleLen : false;
} //获取字符长度
private function getLen($str)
{
return mb_strlen($str,'utf-8');
} //获取部分匹配表
private function getMatchTable()
{
$matchTable = [];
for ($i=0; $i < $this->_needleLen; $i++){
$intersectLen = 0;
$nowStr = mb_substr($this->needle,0,$i + 1,'utf-8');
$preFixArr = $this->getPreFix($nowStr);
$sufFixArr = $this->getSufFix($nowStr);
if($preFixArr && $sufFixArr){
$intersectArr = array_intersect($preFixArr,$sufFixArr);
if (!empty($intersectArr)){
$intersect = array_pop($intersectArr);
$intersectLen = mb_strlen($intersect,'utf-8');
}
}
$matchTable[$i] = $intersectLen;
}
return $matchTable;
} //获取前缀数组
private function getPreFix($str)
{
$outArr = [];
$strLen = $this->getLen($str);
if ($strLen > 1){
for ($i = 1;$i < $strLen; $i++){
$outArr[] = mb_substr($str,0,$i,'utf-8');
}
}
return $outArr;
} //获取后缀数组
private function getSufFix($str)
{
$outArr = [];
$strLen = $this->getLen($str);
if ($strLen > 1){
for ($i = 1;$i < $strLen; $i++){
$outArr[] = mb_substr($str,$i,null,'utf-8');
}
}
return $outArr;
} //计算步长
private function getStep($matchNum,$lastMatchValue)
{
return $matchNum - $lastMatchValue;
} //获取最后匹配值
private function getLastMatchValue($index)
{
return isset($this->_matchTable[$index]) ? $this->_matchTable[$index] : 0;
}
}
$str = 'BBC ABCDAB ABCDABCDABDE';
$subStr = 'ABCDABD';
$kmp = new KMP($str,$subStr);
var_dump($kmp->strpos());
$kmp->haystack = 'i believe';
$kmp->needle = 'lie';
var_dump($kmp->strpos());
$kmp->haystack = 'i love u';
$kmp->needle = 'hate';
var_dump($kmp->strpos());

结论

以上代码就是我看完这篇文章最想做的事-实践。虽然代码不是最好的,但是基本功能实现啦。

PHP通过KMP算法实现strpos的更多相关文章

  1. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  2. KMP算法

    KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...

  3. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  4. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

  5. 数据结构与算法JavaScript (五) 串(经典KMP算法)

    KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配 ...

  6. 扩展KMP算法

    一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...

  7. 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

    之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...

  8. 算法:KMP算法

    算法:KMP排序 算法分析 KMP算法是一种快速的模式匹配算法.KMP是三位大师:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的,所以取首字母组成KMP. 少部分图片来自孤~影 ...

  9. BF算法与KMP算法

    BF(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符:若不相等,则比较S的 ...

随机推荐

  1. window.location.search 为何在url 带# 号时获取不到 ?

    我们在获取url参数时,会常常用到截取参数 getUrlParam(name) { const reg = new RegExp('(^|&)' + name + '=([^&]*)( ...

  2. C#获取文件夹/文件的大小以及占用空间 转摘自:http://www.cnblogs.com/chenpeng-dota/articles/2176470.html

    C#获取文件夹/文件的大小以及占用空间 今天,头给了个任务:写个方法,我会给你个路径,计算这个路径所占用的磁盘空间 . 然后,找了很多资料.但大部分都是获取文件夹/文件的大小的.对于占用空间的没有成品 ...

  3. 【目录】sql server 进阶篇系列

    随笔分类 - sql server 进阶篇系列 sql server 下载安装标记 摘要: SQL Server 2017 的各版本和支持的功能 https://docs.microsoft.com/ ...

  4. python介绍(变量,if,while)

    python介绍(变量,if,while): python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹 打发时间,决心开发一个新 ...

  5. AtCoder Beginner Contest 130 F Minimum Bounding Box 三分法求极值(WA)

    题意:给n个点的起始坐标以及他们的行走方向,每一单位时间每个点往它的方向移动一单位.问最小能包围所有点的矩形. 解法:看到题目求极值,想了想好像可以用三分法求极值,虽然我也不能证明面积是个单峰函数. ...

  6. 2019HDU多校第一场 String 贪心

    题意:给你一个字符串,问是否存在一个长度为m的子序列,子序列中对应字符的数目必须在一个范围内,问是否存在这样的字符串?如果存在,输出字典序最小的那个. 思路:贪心,先构造一个序列自动机,序列自动机指向 ...

  7. [HTML知识体系]meta标签的常见用法

    1.meta是什么 元素可提供有关页面的元信息(meta-information),比如针对搜索引擎和更新频度的描述和关键词. 标签位于文档的头部,不包含任何内容. 标签的属性定义了与文档相关联的名称 ...

  8. Vue-cli的安装步骤详细版本

    https://github.com/vuejs/vue-cli 官网 使用官方推荐的webpack 条件:node在4.以上,npm在3以上 安装步骤:1.cmd打开命令行窗口2.输入cnpm in ...

  9. [NOIP模拟测试30]题解

    A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...

  10. 探索Redis设计与实现1:Redis 的基础数据结构概览

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...