简单介绍一下问题

给定source字符串,找出target字符串出现的首位

例如

source   为“abddabddabc”

target  为 “abddabc”

从第一位开始比较 |a b d d a b|d d a b c

         |a b d d a b|c   不匹配

从第二位继续比较 a|b d d a b d d a b c

           |a       不匹配

。。。

。。。

从第五位继续比较 a b d d|a b d d a b c

             a b d d a b c  匹配成功

再给出kmp算法

从第一位开始比较 a b d d a b|d d a b c

         a b d d a b|c  不匹配

————————————————————————————————

观察失配处前两位ab与target的前两位ab一致,

而整个target不再出现ab,所以即使出现匹配,也只能出现在最后两位

也就是ab之后,所以我们可以直接跳过中间所有位

直接把target的前两位与source当前ab对齐,继续匹配

————————————————————————————————

第二次匹配        a b d d| a b|| d d a b c 

                   | a b||d d a b c 

其中单斜杠处即为所求 双斜杠处为第二次匹配起始位

在上个例子 两条长横线中的内容就是kmp的核心思路:

不需要每一次失配都只从下一位继续,

只需要对比首位的重合部分,移动target,使其首尾重合部分对其,即可继续对比

再举一个极端的例子,便于理解

target 为 abcdefgh

如果source存在匹配部分,那这部分必由a起始

所以在匹配的过程中,发生了失配,即可全部跳过,对比下一位是否为a

而对于首尾有重合部分,则需要从重合部分下一位开始,而重合部分的起始位即为所求

重新用自然语言描述一下我们要做的事:

1  开始匹配 如果完成匹配 返回重合的起始位

2  发生失配 从当前失配位 观察target的首尾重合部分

3     调整target到重合部分首位 从失配位继续匹配

而失配位前target的首尾重合部分的长度由target自身决定,举例说明

  a b d d a b d d a b c

  0 1 2 3 4 5 6 7 8 9 10

  0 0 0 0 1 2 3 4 1 2 0

比如当source为

  a b d d a b d d c c c c c c c c c

  0 1 2 3 4 5 6 7 8 9 10

  0 0 0 0 1 2 3 4 1 2 0

a b d d a b d d a b c

我们在第八位发生失配,那么在0+8-4位为起始,从target的4 位继续匹配即可

下面给出java代码实现:

package cn.baqn.selfstudy;
public class Solution {
 public static void main(String[] args) {
  String source="abddabkdabc";
  String target="abddabc";
  int a=Solution.strStr(source, target);
  System.out.println(a);
 }
 public static int strStr(String source, String target) {
  if(target=="") {
   return 0;
  }
  if(source.length()<target.length()) {
   return -1;
  }
  int[] next=nextKmp(target);
  int j=0;
  int i=0;
  while(true){
   while(j<target.length()&&(i+j)<source.length()&&source.charAt(i+j)==target.charAt(0+j)) {
    //System.out.println(source.charAt(i+j));
    j++;
   }
   if(j==target.length()) {
    System.out.println("!");
    return i;
   }
   if((i+j)==source.length()) {
    return -1;
   }
   if(j==0) {
    i++;
    continue;
   }
   i=i+j-next[j-1];
   j=next[j-1];
   
   
  }
    }
 public static int[] nextKmp(String str) {
  if(str.equals("")) {
   return null;
  }
  int[] next=new int[str.length()];
  for (int i = 0; i < next.length; i++) {
   next[i]=0;
  }
  for (int i = 1; i < str.length(); ) {
   int j=0;
   while((i+j)<str.length()&&str.charAt(i+j)==str.charAt(0+j)) {
    next[i+j]=j+1;
    j++;
   }
   if(j==0) {
    i++;
   }else {
    i+=j; 
   }
  }
  return next;
 }
}

    

一个简易的kmp教学并给出java实现的更多相关文章

  1. Java实践:一个简易的http server和client的java源码学习和总结。

    一.基本思路: 1.服务器端通过socket(), 监听在TCP 8080端口,等待客户端来连接. 2.服务器端解析客户端的HTTP请求中的URI值,把本地的目录下指定文件通过java的读取文件的方式 ...

  2. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  3. 自己来实现一个简易的OCR

    来做个简易的字符识别 ,既然是简易的 那么我们就不能用任何的第三方库 .啥谷歌的 tesseract-ocr, opencv 之类的 那些玩意是叼 至少图像处理 机器视觉这类课题对我这种高中没毕业的人 ...

  4. 探秘Tomcat——一个简易的Servlet容器

    即便再简陋的服务器也是服务器,今天就来循着书本的第二章来看看如何实现一个servlet容器. 背景知识 既然说到servlet容器这个名词,我们首先要了解它到底是什么. servlet 相比你或多或少 ...

  5. ENode 2.0 - 第一个真实案例剖析-一个简易论坛(Forum)

    前言 经过不断的坚持和努力,ENode 2.0的第一个真实案例终于出来了.这个案例是一个简易的论坛,开发这个论坛的初衷是为了验证用ENode框架来开发一个真实项目的可行性.目前这个论坛在UI上是使用了 ...

  6. 使用MVVM框架avalon.js实现一个简易日历

    最近在做公司内部的运营管理系统,因为与日历密切相关,同时无需触发条件直接显示在页面上,所以针对这样的功能场景,我就用avalon快速实现了一个简易日历,毕竟也是第一次造日历这种轮子,所以这里记录下我当 ...

  7. C 实现一个简易的Http服务器

    引言 做一个老实人挺好的,至少还觉得自己挺老实的. 再分享一首 自己喜欢的诗人的一首 情景诗. 每个人总会有问题,至少喜欢就好, 本文 参照 http 协议   http://www.cnblogs. ...

  8. avalon.js实现一个简易日历

    使用MVVM框架avalon.js实现一个简易日历   最近在做公司内部的运营管理系统,因为与日历密切相关,同时无需触发条件直接显示在页面上,所以针对这样的功能场景,我就用avalon快速实现了一个简 ...

  9. Tinychatserver: 一个简易的命令行群聊程序

    这是学习网络编程后写的一个练手的小程序,可以帮助复习socket,I/O复用,非阻塞I/O等知识点. 通过回顾写的过程中遇到的问题的形式记录程序的关键点,最后给出完整程序代码. 0. 功能 编写一个简 ...

随机推荐

  1. 2017-10-31 中文代码示例教程之Vuejs入门&后续计划

    "中文编程"知乎专栏原链 为了检验中文命名在主流框架中的支持程度, 这里把vuejs官方入门教程第一部分的示例代码中尽量使用了中文命名. 过程中有一些发现, 初步看来Vuejs对中 ...

  2. SQL Server排名或排序的函数

    SQL Server获得排名或排序的函数有如下几种: 1.Rank():在结果集中每一条记录所在的排名位置,但排名可能不连续,例如:若同一组内有两个第一名,则该组内下一个名次直接跳至第三名   sel ...

  3. Java Socket聊天室编程(一)之利用socket实现聊天之消息推送

    这篇文章主要介绍了Java Socket聊天室编程(一)之利用socket实现聊天之消息推送的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下 网上已经有很多利用socket实现聊天的例子了 ...

  4. 吴恩达机器学习笔记59-向量化:低秩矩阵分解与均值归一化(Vectorization: Low Rank Matrix Factorization & Mean Normalization)

    一.向量化:低秩矩阵分解 之前我们介绍了协同过滤算法,本节介绍该算法的向量化实现,以及说说有关该算法可以做的其他事情. 举例:1.当给出一件产品时,你能否找到与之相关的其它产品.2.一位用户最近看上一 ...

  5. Redis集群架构

    Redis集群概述 集群的核心意义只有一个:保证一个节点出现了问题之后,其他的节点可以继续提供服务使用. Redis基础部分讲解过主从配置:对于主从配置可以有两类:一主二从,层级关系.开发者一主二从是 ...

  6. linux入门--操作系统是什么,操作系统概述

    Linux 也是众多操作系统之一,要想知道 Linux 是什么,首先得说一说什么是操作系统. 计算机是一台机器,它按照用户的要求接收信息.存储数据.处理数据,然后再将处理结果输出(文字.图片.音频.视 ...

  7. Android开发:UI相关(一)自定义样式资源

    一.自定义样式资源:   1.在drawble中新建xml资源文件:     如果新建的xml文件没有自动放置在drawable文件夹下,就手动移动到drawable下. 2.编写样式代码: < ...

  8. AI - TensorFlow - 分类与回归(Classification vs Regression)

    分类与回归 分类(Classification)与回归(Regression)的区别在于输出变量的类型.通俗理解,定量输出称为回归,或者说是连续变量预测:定性输出称为分类,或者说是离散变量预测. 回归 ...

  9. Linux 进程终止后自动重启

    /opt/a.sh #! /bin/bash ps -ef | grep python3 a.py | grep -v grep | grep python3 if [ $? -ne 0 ] then ...

  10. [macOS开发.NET Core] 开篇 & 抉择 & 先利其器

    一直以来MacBook是大多数开发者的首选,无论是macOS的便利性,还是MBP的外观,更或者是为了装13,我一直认为一个开发者必须得拥有一部MBP.虽然最后的因素是大多数的. 终于在我的努力下说服下 ...