复习一下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. 【学习】js学习笔记:数组(二)

    二维数组 例子:矩形反转: <script> var arr=[[1,1,1,1,1],[2,2,2,2,2],[3,3,3,3,3],[4,4,4,4,4],[5,5,5,5,5]]; ...

  2. CSS之 float 属性

    特性: float的设计初衷仅仅是文字环绕效果  浮动具有破坏性,会使父容器高度塌陷  清除浮动方法: 1.脚底插入cleart:both 2.父元素BFC(IE8+)/haslayout(IE6/7 ...

  3. fedora 19 gnome 3.8 关闭笔记本盖子的动作

    gnome-tweak-tool里没有了相关选项,但是又想让关闭盖子不挂起,后来看看才知道gnome3.8不再提供这功能,而是交给systemd来处理,所以估计用dconf-edit在gnome的po ...

  4. python第四课——线程、进程、协程

    面试or笔试题:简述线程.进程.协程之间的关系? 内容概要 1.进程与线程优.缺点的比较 2.适用情况 3.线程 线程的创建 setDaemon join event RLock 队列 4.进程 创建 ...

  5. 已安装Fedora的U盘无法格式化,要求reinitialize layout

    错误提示:This partition cannot be modified because it contains a partition table; >please reinitializ ...

  6. LeetCode 104. Maximum Depth of Binary Tree (二叉树的最大深度)

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  7. mysql中多个left join子查询写法以及别名用法

    不多说 直接上语句   SELECT     a.id,     a.thumbNail,     a. NAME,     a.marketPrice,     a.memberPrice,     ...

  8. sql语句如何查询一个表中某两个字段的相同数据?

    Select Name,ID From A group by Name,ID having count (*)>1

  9. 数据模型(LP32 ILP32 LP64 LLP64 ILP64 )

    数据模型(LP32 ILP32 LP64 LLP64 ILP64 ) 32位环境涉及"ILP32"数据模型,是因为C数据类型为32位的int.long.指针.而64位环境使用不同的 ...

  10. zabbix 2.2.20 安装详解(Centos6.9)

    环境说明 [root@centos ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@centos ~]# uname -a L ...