复习一下KMP算法

KMP的主要思想是利用字符串自身的前缀后缀的对称性,来构建next数组,从而实现用接近O(N)的时间复杂度完成字符串的匹配

对于一个字符串str,next[j] = k 表示满足str[0...k-1] = str[j-k...j-1]的最大的k,即对于子串str[0...j-1],前k个字母等于后k个字母

现在求解str的next数组:

初始化:next[0] = -1

那么在知道了next[j]的情况下,如何递推地求出next[j+1]呢?分两种情况(令k=next[j]):

  1、如果str[j]==str[k],则next[j+1] = k+1

  如下图所示,对于str[0...j-1],前k个字母等于后k个字母(两个绿色部分相等),然后str[k]刚好是前k个字母的下一个字母(第一个红色)

  如果str[j]==str[k],说明对于str[0...j],前k+1个字母等于后k+1个字母(绿色+红色=绿色+红色),即等于next[j]+1(绿色长度为k,红色长度为1)

  2、如果str[j]!=str[k],则k=next[k],然后继续循环(回到1),直到k=-1

  因为str[j]!=str[k](下图中紫色和红色不相等),所以前k+1个字母不再等于后k+1个字母了

  但是由于前k个字母还是等于后k个字母(图中两个黑色虚线框住部分),所以对于任意的k'<k,str[k-k'...k-1]=str[j-k'...j-1](图中第二个和最后一个绿色相等)

  而next[k]表示str[0...k-1]内部的对称情况,所以令k'=next[k],则对于str[0...k-1],前k'个字母等于后k'个字母(图中第一个和第二个绿色相等)

  由于图中第二个绿色始终=第四个绿色,所以第一个绿色等于第四个绿色

  因此将k=next[l]继续带入循环,回到判断1:

    如果str[k']=str[j],则满足前k'+1个字母等于后k'+1个字母(两个浅黄色区域相等),所以next[j+1] = k'+1;

    否则,继续k'=next[k']继续循环,直到k'=-1说明已经到达第一个元素,不能继续划分,next[j+1]=0

 

得到了求next数组的递推方法后,现在用C++实现

void getNext( string str, int next[] )
{
int len = str.length();
next[0] = -1;
int j = 0, k = -1;
while( j<len-1 )
{
if( k==-1 || str[j]==str[k] )
next[++j] = ++k;
else
k = next[k];
}
}

这里解释一下:由于每一轮赋值完next[j]后,k要不然是-1,要不然是next[j](上次匹配的前缀的下一个位置)

如果k=-1,说明next[j+1]=0=k+1;否则如果str[j]==str[k],说明前k+1个字母等于后k+1个字母,直接next[j+1]=k+1

所以循环中if后的语句为“next[++j] = ++k;”

现在用求解next数组的思路解决leetcode上的一道题

https://leetcode.com/problems/repeated-substring-pattern/

Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000

Example:

Input: "abcabcabcabc"

Output: True

Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.)

假设str长度为len,重复的子串长度为k,则如果真的由连续多个长度为k的子串重复构成str,那么在对str求next时,由于连续对称性(如图,前后两个虚线框内字符串相等),会从next[k+1]开始,1,2,3...地递增,直到next[len]=len-k,且(len-k)%k==0,表示有整数个k

要一直求到next[len]而不是next[len-1],是因为next[len-1]只是表示前len-1个字母的内部对称性,而没有考虑到最后一个字母即str[len-1]

所以求解很简单:先对str求next数组,一直求到next[len],然后看看next[len]是否非零且整除k(k=len-next[len])

bool repeatedSubstringPattern(string str)
{
int len = str.length();
int next[len+1];
next[0] = -1;
int j = 0, k = -1;
while( j<len )
{
if( k==-1 || str[j]==str[k] )
next[++j] = ++k;
else k = next[k];
}
return next[len]&&next[len]%(len-next[len])==0;
}

时间复杂度只有O(N),而暴力需要O(N^2)

KMP - LeetCode #459 Repeated Substring Pattern的更多相关文章

  1. 43. leetcode 459. Repeated Substring Pattern

    459. Repeated Substring Pattern Given a non-empty string check if it can be constructed by taking a ...

  2. [LeetCode] 459. Repeated Substring Pattern 重复子字符串模式

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  3. LeetCode - 459. Repeated Substring Pattern - O(n)和O(n^2)两种思路 - KMP - (C++) - 解题报告

    题目 题目链接 Given a non-empty string check if it can be constructed by taking a substring of it and appe ...

  4. LeetCode 459 Repeated Substring Pattern

    Problem: Given a non-empty string check if it can be constructed by taking a substring of it and app ...

  5. 459. Repeated Substring Pattern【easy】

    459. Repeated Substring Pattern[easy] Given a non-empty string check if it can be constructed by tak ...

  6. 459. Repeated Substring Pattern

    https://leetcode.com/problems/repeated-substring-pattern/#/description Given a non-empty string chec ...

  7. *459. Repeated Substring Pattern (O(n^2)) two pointers could be better?

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  8. 【LeetCode】459. Repeated Substring Pattern

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  9. 【LeetCode】459. Repeated Substring Pattern 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 遍历子串 日期 [LeetCode] 题目地址:ht ...

随机推荐

  1. HTTP错误代码大全

    HTTP出错大全 101 - Switching Protocols Top Success Codes 200 - OK201 - Created202 - Accepted203 - Non-Au ...

  2. SAP 发送邮件 面向对象

    REPORT ZMMR0068_YYN. CONSTANTS: gc_tab TYPE c VALUE cl_bcs_convert=>gc_tab, "CL_ABAP_CHAR_UT ...

  3. win10 UWP 单元测试

    我们在写代码的时候不能保证我们写出来的代码是正确的,所以我们经常要单元测试. 单元测试和重构都是在做完一个小小函数一般就要进行一次,越早做就越好,可以比较早发现问题,这时我们还记得我们写的内容,不过比 ...

  4. jfinal编码问题及解决

    使用jfinal出现了常见的编码问题情况 public void test() { Random r = new Random(); try { Connection conn = createCon ...

  5. 购物篮算法的理解-基于R的应用

    是无监督机器学习方法,用于知识发现,而非预测,无需事先对训练数据进行打标签,因为无监督学习没有训练这个步骤.缺点是很难对关联规则学习器进行模型评估,一般都可以通过肉眼观测结果是否合理. 一,概念术语 ...

  6. 损失函数&经验函数

    损失函数:度量模型一次预测的好坏 经验函数:度量模型平均意义下的预测好坏 输出预测值F(x)与实际值Y可能不一致也可能一致,损失函数(Loss function)可以度量一次预测,记作L(Y,F(x) ...

  7. LINUX 笔记-read命令

    作用:读入值给变量 1.read  从键盘读入字符到name变量 2.read -p 'msg' var... 输入提示 3.read -s vars 隐藏输入 4.read读取文件时,每次调用会读取 ...

  8. 写一个类时什么时候需要重写toString

    一般需要打印出来的时候需要重写toString方法 例如:User.java类 public class User { private String name; @Value(value=" ...

  9. ios微信支付 v3

    V2版本和V3版本存在很大的差异. 1. 从成功通过微信支付商户的资料审核返回的邮件开始: 你可以获得这些参数  appid,appSecret,partnerID,    partnerKey(从平 ...

  10. Dapper.Contrib——更加优雅地使用Dapper进行增删改查

    简介 Dapper是介于Entity framework与ADO的折中选择.既满足手写查询的高性能需求,又简化了数据库对象映射为内存对象的繁杂工作.Dapper.Contrib是对Dapper的进一步 ...