【数据结构&&等差数列】KMP简介和算法的实现(c++ && java)
发布日期:2021-06-24 18:09:01 浏览次数:2 分类:技术文章

本文共 3814 字,大约阅读时间需要 12 分钟。

KMP算法假定了解案件的原则,其实很easy。

KMP算法简述

关于根据自己的理解在这里。

KMP该算法由三个发明人的名称(Knuth、Morris、Pratt)的首字母组成,又称字符串查找算法。

个人认为能够理解为最小回溯算法,即匹配失效的时候,尽量少回溯。从而缩短时间复杂度。

KMP算法有两个关键的地方。1)求解next数组。2)利用next数组进行最小回溯。

1)求解next数组

next数组的取值仅仅与模式串有关。next数组用于失配时回溯使用。

在简单版本号的KMP算法中,每一个位置 j 的 next 值表示的是
模式串的最长前缀的最后一个字符的位置(如果为 k ),当中最长前缀(长度为 k+1 )须要与模式串截至当前位置长度亦为 k+1 的后缀匹配。且 k 最大为 j-1 ,否则相当于没有回溯。

当k=-1的时候。表示找不到这种最长前缀。

用公式表示为
当k=-1的时候。表示空串。p表示模式串。

以下举一个计算next数组的样例,如果模式串是 “ abaabcaba ” 。
j 0 1 2 3 4 5 6 7 8
p a b a a b c a b a
next[j] -1 -1 0 0 1 -1 0 1 2
以 j = 8 为例,最长前缀为aba,最后一个字符位置为2,故 next[8] = 2 。
那么怎样高速求解next数组呢?
这里有点
动态规划的思想在里面,当中位置 j 等于 0 的 next 值为-1,表示找不到这种最长前缀。 j > 0 时。next值能够通过 j - 1 位置的next值求得。
求解next[ j ]的步骤:
  1. t = next[ j - 1 ] + 1,t 指向可能等于 p[ j ] 的位置,即 p[ t ] 可能等于 p[ j ]。

  2. 假设 p[ t ]   =  p[ j ] , 那么 next[ j ] = next[ j - 1 ] + 1
  3. 假设 p[ t ]  !=  p[ j ] , 则令 t = next[ t - 1 ] + 1,继续第 2 步直到 t = 0 或者找到位置。

  4. 结束时推断p[ t ] 是否等于 p[ j ] ,假设等于则 next[ j ] = t , 否则等于 -1 。

下图表示了第一次不匹配。第二次匹配的过程,其他过程能够类推。当中     或     覆盖部分表示最长匹配串。   为待判定位置,    为已判定位置。

0123                                                     j
×××××××××××××
×××××××××××××× ×××××××××××××
×
×××× × ×××× ×××× ×××××××××××××× ××××××××× ××××
×

2)利用next数组进行最小回溯

s ××××××××××××××××××××××××××××××××××××××××××××

p                                            ××××××××××××××

在j处不失配时,前面的有部分匹配。这时须要利用next数组信息进行最小回溯。

s ××××××××××××××××××××××××××××××××××××××××××××

p                                            ××××××××××××××

(这里 i 指向 s , j 指向 p。)

注意在 j = 0 的时候失配时。直接 i++ 就可以。

当 j > 0 的时候,须要利用next数组最快找到 p[ j ] == s[ i ] 的位置。

假设 j 移动到了0还找不到。则 i++,然后继续匹配。

这里我们能够发现仅仅有 j 回溯了,i没有回溯,可是因为普通版本号的 KMP 算法 j 须要不停地回溯直到找到合适的回溯位置,因此速度不是特别快。还能够继续优化。感兴趣的读者能够想想怎样事先求解好next数组从而不须要不停地回溯。

代码实现

strStr返回的是首次匹配的地址。假设不能匹配则返回NULL。

class Solution {public:    vector
getNext(char* &s){ vector
next(strlen(s), -1); for(int i=1; i
=0) j = next[j]; if(s[j+1] == s[i]) next[i] = j+1; // else 默觉得-1 } return next; } char *strStr(char *haystack, char *needle) { if(haystack==NULL || needle==NULL) return NULL; if(strlen(haystack) < strlen(needle)) return NULL; if(strlen(needle) == 0) return haystack; vector
next = getNext(needle); int i = 0; int j = 0; int haystackLen = strlen(haystack); int needleLen = strlen(needle); while(i

因为有人问有没有java版本号的,因为鄙人java比較挫。写java时部分还写成了scala的语法。不知道代码是否规范,有优化的地方还麻烦java方面的大神指点。

import java.util.*;public class StrStrSolution {    private List
getNext(String p){ List
next = new ArrayList
(); next.add(-1); for(int i=1; i
=0) j = next.get(j); if(p.charAt(j+1) == p.charAt(i)) next.add( j + 1 ); else next.add( -1 ); } return next; } public String strStr(String haystack, String needle) { if (haystack == null || needle == null) return null; if (needle.length() == 0) return haystack; if (needle.length() > haystack.length()) return null; List
next = getNext(needle); int i = 0; int j = 0; int haystackLen = haystack.length(); int needleLen = needle.length(); while(i < haystackLen && j < needleLen){ if(haystack.charAt(i) == needle.charAt(j) ) { i++; j++; if(j == needleLen) return haystack.substring(i - j); }else{ if(j==0) i++; else j = next.get(j-1)+1; } } return null; } public static void main(String[] args) { String s = "babcabaabcacbac"; String p = "abaabcac"; StrStrSolution sol = new StrStrSolution(); System.out.println(sol.strStr(s,p)); }}

转载地址:https://blog.csdn.net/weixin_34248258/article/details/85783295 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:php获取当前月月初至月末的时间戳,上个月月初至月末的时间戳
下一篇:Leetcode: Spiral Matrix. Java

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年03月30日 21时45分49秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章