数据结构-BF算法及KMP算法

BF算法

代码

<?php
function bf($s,$t){
    $i=0;
    $j=0;
    $k;
    while($i<strlen($s) && $j<strlen($t)){
        if($s[$i] == $t[$j]){
            $i++;
            $j++;

        }else{
            $i = $i - $j + 1;
            $j = 0;;
        }
        
    }    
    if($j >= strlen($t)) $k = $i - strlen($t);
    else $k = -1;
    return $k;    
}
$str1 = "abaabcabclkjlkff";
$str2 = "abc";
echo bf($str1,$str2);
?>

复杂度

最坏状况的时间复杂度O(m*n)。m为模式串长度。n为目标串长度。php

KMP算法

代码

<?php
function GetNext($t,&$next){
    $j = 0;
    $k = -1;
    $next[0] = -1;
    while($j<strlen($t)){
        if($k==-1||$t[$j] == $t[$k]){
            $j++;
            $k++;
            $next[$j]=$k;
        }
        else $k = $next[$k];
    }
//    var_dump($next);
}
function KMPIndex($s,$t){
    $i = 0;
    $j = 0;
    $v;
    $next = [];
    GetNext($t,$next);
//    var_dump($next);
    while($i<strlen($s) && $j<strlen($t)){
        if($j==-1 || $s[$i]==$t[$j]){
            $i++;
            $j++;
        }else{
            $j = $next[$j];
        }
    }
    if($j>=strlen($t)) $v = $i - strlen($t);
    else $v = -1;
    return $v;
}

$s="ababcabcacbab";
$t="abcac";
$k;
$k = KMPIndex($s,$t);
echo $k;
?>

时间复杂度

时间复杂度为O(m+n)。m为模式串长度。n为目标串长度。
算法简单记忆分为两步:1.模式串扫描,生成next数组,O(m)。2.主串扫描,匹配,O(n)。
KMP算法对BF算法的回溯问题进行了改进,在整个匹配过程当中对主串仅需从头到尾扫描一遍。java

其余

  1. php函数参数传递。在定义函数时在参数前加上'&'改成引传递。通常状况为值传递,对象除外。算法

  2. php在字符串索引某个字符。若包含中文字符须要另行处理。js能够经过"[]"直接索引。java用charat函数。数组

  3. BM算法。函数

思考

看一个生成next数组的简单例子。
考虑模式串t="abab",观察一下next数组的生成过程。指针

  1. 初始化。j=0 k=-1 next[0]=-1code

  2. 第一趟。j=1 k=0 next[1]=0对象

  3. 第二趟。k=next[0]=-1索引

  4. 第三趟。j=2 k=0 next[2]=0字符串

  5. 第四趟。匹配。j=3 k=1 next[3]=1

  6. 第五趟。匹配。j=4 k=2 next[4]=2

这里首先能够注意到在第六步中j=4,而实际在咱们的模式串"abab"中4这个下标已经越界了,嗯嗯,不要着急,咱们先来看看在每一趟循环中到底作了什么。

if($k==-1||$t[$j] == $t[$k]){
            $j++;
            $k++;
            $next[$j]=$k;
        }
        else $k = $next[$k];

代码不过5行,一个if...else...的判断语句。假设看的同窗已经在其余地方看过这里先后缀的原理了。
若是k=-1或t[j]=t[k],j++,k++,next[j]=k。
这里的k=-1暂时不考虑他的做用,那么就是若是主串(模式串)与子串中的字符匹配,则主串指针向后一位,子串指针向后一位,给next数组赋值。
不然k=next[k]。不然向前移动子串指针。这里也是根据next数组移动子串指针而且须要注意抽象出子串的概念。

因此在第六步中匹配成功之后主串子串移动,在这以后已经跳出循环了。而实际上next[4]在目标串中匹配是用不到的。

嗯。。要记住是先尝试匹配,成功后在向后移动指针,不匹配则重置指针。

这里的k=-1能够理解为当首位不匹配时移动指针的一个条件。

紧接着能够思考模式串"abcab","abcabd","ababab"等next数组的生成过程。理解kmp的重点在于next数组是如何生成的。

相关文章
相关标签/搜索