[每天默写一个算法]KMP

作业要求:默写String的KMP算法。

KMP是经典的字符串匹配算法。复杂度为O(n+m)

     public static class StringKMP
{
/// <summary>
/// This indicates that no pattern found from source.
/// </summary>
public const int KMPNoMatch = -;
/// <summary>
/// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
/// </summary>
public const int FirstBlood = -;
/// <summary>
/// Find first match for specified pattern in the source.
/// </summary>
/// <param name="source"></param>
/// <param name="pattern"></param>
/// <returns></returns>
public static int KMP(this String source, String pattern)
{
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
{ return KMPNoMatch; }
var i = ; var j = ; var result = KMPNoMatch;
var nextVal = GetNextVal(pattern); while (i < source.Length && j < pattern.Length)
{
if (j == FirstBlood)
{// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
i++; j = ;
}
else if (source[i].Equals(pattern[j]))
{
i++; j++;
}
else
{// Get next j that should be compared with.
j = nextVal[j];
}
} if (j >= pattern.Length)// Match succeeded.
{ result = i - pattern.Length; } return result;
}
/// <summary>
/// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
/// <para>if source[i] does NOT equal with pattern[j].</para>
/// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
/// <para>and j should be reset to 0.</para>
/// <para>So we should always set nextVal[0] = FirstBlood.</para>
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static int[] GetNextVal(String pattern)
{
var j = ; var k = -;
var nextVal = new int[pattern.Length]; nextVal[] = FirstBlood; while (j < pattern.Length - )
{
if ((k == -) || (pattern[j].Equals(pattern[k])))
{
j++; k++;
if (!(pattern[j].Equals(pattern[k])))
{ nextVal[j] = k; }
else
{ nextVal[j] = nextVal[k]; }
}
else
{ k = nextVal[k]; }
} return nextVal;
}
}

字符串能匹配,其他类型的串(数组Array和泛型数组IList<T>)也就可以匹配。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace System
{
public static class StringKMP
{
/// <summary>
/// This indicates that no pattern found from source.
/// </summary>
public const int KMPNoMatch = -;
/// <summary>
/// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
/// </summary>
private const int FirstBlood = -;
/// <summary>
/// Find first match for specified pattern in the source.
/// </summary>
/// <param name="source"></param>
/// <param name="pattern"></param>
/// <returns></returns>
public static int KMP(this String source, String pattern)
{
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(pattern))
{ return KMPNoMatch; }
var i = ; var j = ; var result = KMPNoMatch;
var nextVal = GetNextVal(pattern); while (i < source.Length && j < pattern.Length)
{
if (j == FirstBlood)
{// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
i++; j = ;
}
else if (source[i].Equals(pattern[j]))
{
i++; j++;
}
else
{// Get next j that should be compared with.
j = nextVal[j];
}
} if (j >= pattern.Length)// Match succeeded.
{ result = i - pattern.Length; } return result;
}
/// <summary>
/// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
/// <para>if source[i] does NOT equal with pattern[j].</para>
/// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
/// <para>and j should be reset to 0.</para>
/// <para>So we should always set nextVal[0] = FirstBlood.</para>
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static int[] GetNextVal(String pattern)
{
var j = ; var k = -;
var nextVal = new int[pattern.Length]; nextVal[] = FirstBlood; while (j < pattern.Length - )
{
if ((k == -) || (pattern[j].Equals(pattern[k])))
{
j++; k++;
if (!(pattern[j].Equals(pattern[k])))
{ nextVal[j] = k; }
else
{ nextVal[j] = nextVal[k]; }
}
else
{ k = nextVal[k]; }
} return nextVal;
}
} public static class ArrayKMP
{
/// <summary>
/// This indicates that no pattern found from source.
/// </summary>
public const int KMPNoMatch = -;
/// <summary>
/// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
/// </summary>
private const int FirstBlood = -;
/// <summary>
/// Find first match for specified pattern in the source.
/// </summary>
/// <param name="source"></param>
/// <param name="pattern"></param>
/// <returns></returns>
public static int KMP(this Array source, Array pattern)
{
if (source == null || pattern == null || source.Length == || pattern.Length == )
{ return KMPNoMatch; }
var i = ; var j = ; var result = KMPNoMatch;
var nextVal = GetNextVal(pattern); while (i < source.Length && j < pattern.Length)
{
if (j == FirstBlood)
{// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
i++; j = ;
}
else if (source.GetValue(i).Equals(pattern.GetValue(j)))
{
i++; j++;
}
else
{// Get next j that should be compared with.
j = nextVal[j];
}
} if (j >= pattern.Length)// Match succeeded.
{ result = i - pattern.Length; } return result;
}
/// <summary>
/// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
/// <para>if source[i] does NOT equal with pattern[j].</para>
/// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
/// <para>and j should be reset to 0.</para>
/// <para>So we should always set nextVal[0] = FirstBlood.</para>
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static int[] GetNextVal(Array pattern)
{
var j = ; var k = -;
var nextVal = new int[pattern.Length]; nextVal[] = FirstBlood; while (j < pattern.Length - )
{
if ((k == -) || (pattern.GetValue(j).Equals(pattern.GetValue(k))))
{
j++; k++;
if (!(pattern.GetValue(j).Equals(pattern.GetValue(k))))
{ nextVal[j] = k; }
else
{ nextVal[j] = nextVal[k]; }
}
else
{ k = nextVal[k]; }
} return nextVal;
}
} public static class IListKMP
{
sealed class DefaultComparer<T> : IComparer<T>
{
private static readonly DefaultComparer<T> instance = new DefaultComparer<T>(); public static DefaultComparer<T> Instance
{
get { return DefaultComparer<T>.instance; }
} int IComparer<T>.Compare(T x, T y)
{
if (x.Equals(y)) { return ; }
else { return ; }
}
} /// <summary>
/// This indicates that no pattern found from source.
/// </summary>
public const int KMPNoMatch = -;
/// <summary>
/// Special value of next[] array, which means i should be increased by 1 and j sould be reset to 0.
/// </summary>
private const int FirstBlood = -;
/// <summary>
/// Find first match for specified pattern in the source.
/// </summary>
/// <param name="source"></param>
/// <param name="pattern"></param>
/// <param name="comparer"></param>
/// <returns></returns>
public static int KMP<T>(this IList<T> source, IList<T> pattern, IComparer<T> comparer = null)
{
if (source == null || pattern == null || source.Count == || pattern.Count == )
{ return KMPNoMatch; } if (comparer == null) { comparer = DefaultComparer<T>.Instance; } var i = ; var j = ; var result = KMPNoMatch;
var nextVal = GetNextVal(pattern, comparer); while (i < source.Count && j < pattern.Count)
{
if (j == FirstBlood)
{// source[i] does NOT equal with pattern[0], so i should be increased by 1 and j should be reset to 0.
i++; j = ;
}
else if (comparer.Compare(source[i], pattern[j]) == ) //(source[i].Equals(pattern[j]))
{
i++; j++;
}
else
{// Get next j that should be compared with.
j = nextVal[j];
}
} if (j >= pattern.Count)// Match succeeded.
{ result = i - pattern.Count; } return result;
} /// <summary>
/// nextVal[j]: source[i] should compare with pattern[ nextVal[j] ] in next loop
/// <para>if source[i] does NOT equal with pattern[j].</para>
/// <para>Specially, if source[i] does NOT equal with pattern[0], then i should be increased by 1</para>
/// <para>and j should be reset to 0.</para>
/// <para>So we should always set nextVal[0] = FirstBlood.</para>
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
private static int[] GetNextVal<T>(IList<T> pattern, IComparer<T> comparer)
{
var j = ; var k = -;
var nextVal = new int[pattern.Count]; nextVal[] = FirstBlood; while (j < pattern.Count - )
{
if ((k == -) || (comparer.Compare(pattern[j], pattern[k]) == ))
{
j++; k++;
if (!(comparer.Compare(pattern[j], pattern[k]) == ))
{ nextVal[j] = k; }
else
{ nextVal[j] = nextVal[k]; }
}
else
{ k = nextVal[k]; }
} return nextVal;
} } }

[每天默写一个算法]KMP的更多相关文章

  1. 数据结构与算法--KMP算法查找子字符串

    数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...

  2. 经典算法 KMP算法详解

    内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...

  3. 笔记-算法-KMP算法

    笔记-算法-KMP算法 1.      KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...

  4. 值得花费一周研究的算法 -- KMP算法(indexOf)

    KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...

  5. 介绍对称加密的另一个算法——PBE

    除了DES,我们还知道有DESede(TripleDES,就是3DES).AES.Blowfish.RC2.RC4(ARCFOUR)等多种对称加密方式,其实现方式大同小异,这里介绍对称加密的另一个算法 ...

  6. 推荐一个算法编程学习中文社区-51NOD【算法分级,支持多语言,可在线编译】

    最近偶尔发现一个算法编程学习的论坛,刚开始有点好奇,也只是注册了一下.最近有时间好好研究了一下,的确非常赞,所以推荐给大家.功能和介绍看下面介绍吧.首页的标题很给劲,很纯粹的Coding社区....虽 ...

  7. cc150:实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针

    实现一个算法来删除单链表中间的一个结点,仅仅给出指向那个结点的指针. 样例: 输入:指向链表a->b->c->d->e中结点c的指针 结果:不须要返回什么,得到一个新链表:a- ...

  8. 设单链表中存放n个字符,试设计一个算法,使用栈推断该字符串是否中心对称

    转载请注明出处:http://blog.csdn.net/u012860063 问题:设单链表中存放n个字符.试设计一个算法,使用栈推断该字符串是否中心对称,如xyzzyx即为中心对称字符串. 代码例 ...

  9. python学习:设计一个算法将缺失的数字找出来。

    算法题   已知整型数值 a[99], 包含的所有99个元素都是从1-100中随机取值,并且这99个数两两互不相等,也就是说从1到100这100个数字有99个在数值内,有一个缺失.请设计一个算法将缺失 ...

随机推荐

  1. 【Java】:ehcache

    ehcache是一个纯Java进程内缓存框架,是hibernate默认的Cacheprovider.(出自百度百科). 1. 快速2. 简单3. 多种缓存策略4. 缓存数据有两级:内存和磁盘,因此无需 ...

  2. 1 Java线程的内存可见性

    Java内存的可见性 可见性: 一个线程对共享变量的修改,能够及时被其它线程看到 共享变量: 如果一个变量在多个线程的工作内存中都存在副本,那么这个变量就是这几个线程的共享变量 Java内存模型(JM ...

  3. Ubuntu下deb包的安装方法 (zz)

    Ubuntu下deb包的安装方法 分类: Ubuntu10使用技巧 2010-10-11 23:49 42969人阅读 评论(3) 收藏 举报 ubuntudebdebianlinux deb是deb ...

  4. 关于公司VPN专线接入的一个案例

    最近互通网络技术部门收到一到封邮件,是关于公司VPN接入的问题,问题如下: 条件:A区为办公地点1,其他办公电脑20台,并通过写字楼的宽带接口联通外网. B区为新办公地点2,预设应用.数据库.备份服务 ...

  5. C# 如何给sql数据库的日期字段插入空值

    在C#中声明日期变量时用SqlDateTime类型,引用:using System.Data.SqlTypes; 例子:user.AbortDate = SqlDateTime.Null;

  6. (python) 标准模块sys和os的使用

    一.sys模块 包含了系统的相关的功能.我们来学习sys.argv,它包含命令行参数. 例子:定义了一个add函数,用来实现两个整数的相加. #! coding=utf-8 # usersys.py ...

  7. Codeigniter 在Active Record中限制批量更新数目

    今天手头电商项目有个需求是:将订单中的优惠券自动发放给买家,所以要只更新优惠券表中的某几行数据,查了手册和网络都没有解决办法. 一开始用循环和遍历来做都是错的,因为update语句一下就更新掉所有符合 ...

  8. javacript实现不被浏览器拦截打开新窗口

    情景: 1.用户发送数据到服务器 2.服务器根据用户的数据生成文档 3.服务器把所生成的文档的下载地址提供给用户 4.用户使用的浏览器自动根据下载地址下载文件 实现: 网上搜索查找了下实现方式,就我查 ...

  9. linux下解压被分割的zip文件

    形如被分割的一系列文件:linux.z01, linux.z02, linux.z03, linux.zip 直接右键解压是不行的. 首先合并文件:cat linux.* > linux_all ...

  10. [Python] Removing a non-empty folder

    Removing a non-empty folder You will get an ‘access is denied’ error when you attempt to use os.remo ...