深入理解KMP算法,详细解析KMP算法过程(附代码、13. 字符串查找)

问题描述:
对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。

样例 1:
输入: source = “source” , target = “target”
输出:-1
样例解释: 如果source里没有包含target的内容,返回-1

样例 2:
输入: source = “abcdabcdefg” ,target = “bcd”
输出: 1
样例解释: 如果source里包含target的内容,返回target在source里第一次出现的位置

解答思路:

一:第一想法:
想必大家想到的第一个方法就是:循环遍历source里面的每个值,依次和target里面的每个值比较,比如从source的第0为开始,比对0到targetLength长度的值是否和target的第0位到targetLength的值一一对应,不对应则比对source的第1位往后targetLength长度值和target比较,一直循环到结束

能理解继续往下:

比如说下图:我比对source的第1位到第6位是否和target的第0位到第5位相等,当我比对到第5位的时候,发现和target的目标字符不匹配了,我需要将target整体往后挪一位(相对于source而言)像图2那样,再重新比较source的第2位到第7位和target的第0位到第5位是否相等,见图2
艾pple的图片1
图(1)
艾pple的图片2
图(2)

二:思维跳跃一下

思考:可不可以从图1直接跳到图3呢,

再把图1重新贴出来:
艾pple的图片1
图(1)
在这里插入图片描述
图(3)
从图1直接变成图3意味着:
由原本的target在source的第一位直接挪到第4位(相对于Source而言),此时source的第4位和target的第0位相等,所以直接比较source的第5位和target的第1位,

回顾一下图1:
图1的时候比较到source的第5位和target的第4位的时候发现不匹配,
图3是从source的第5位和target的第1位开始比较,
从图1直接跳转到图3意味着 : source的索引不用变,target的索引更改
可以看出从图1直接到图3可是省略了好几部呢

三:思维跳跃多几下

对于这一部分如果能充分理解图1跳到图2完全没问题的,可以大致瞄瞄就好

我们来思考一下,如果图1中匹配的那一段内容即黄色部分不是abdab而是abdac,像图多1-1那样
在这里插入图片描述
图多1-1

那还能像之前图1直接跳到图3那样,直接跳到图多1-3,然后直接比较source的第5位和target的第1位么,如下图
在这里插入图片描述
图多1-3

很显然不能,此时source的第4位和target的第0位都不匹配,怎么可能存在比较target的第1位和source的第5位的情况呢?

对于图1图3和图多1-1图多1-3我们可以知道当我们出现source的第4位和target的第3位匹配的情况时,能直接跳转到图3的条件只有当target的第0和source的第4相等才可以,也就是target的第0和target的第3相等

之前说过图1是比较到source的第5位和target的第4位,图3是直接从source的第5位和target的第1位开始比较。
这里我们又知道,图1到图3之所以能直接的条件是:target第4位之前2个长度字符串和target的0-第2位字符串相等。

四:总结记录思维

再再说一下,由图1能直接去图3是因为target的0开始2位长度串==第4位往前2位长度字符串

那么我们是不是可以记录一下target第0位往后x个长度串==第y位往前x个字符串,只有有什么好处呢,当我们和source比较到一定位置的时候,发现不匹配了,我们可以像图1-图3那样不改变source的索引,把target移动到合适的位置,继续比较就行了(即那个思维跳转一下)

我们有一个数组,每个数组的索引记为y,数组的值记为x,next[y]=x;比如说对于图1或图3那个target字符串产生的数组next[4]=1(2个长度,但是索引从0开始,所以是1),当target比较到第4位发现和source的特定位不匹配了,那么target的索引改为1,source索引不变,继续比较

上一段很重要哦,结合图1-图3看看

五:产生next[] 值

我们知道next[] 产生的值是target从0到x个字符==y往前x个字符(不包括当前第y位)

0.对于target的第0位来说,第0位往前无值,所以next[0]=0; (表示的意思是当target的第0位和source不匹配时,target的下次要匹配位置依然是0,该是source改变索引的时候了)
在这里插入图片描述
图next-1
1.对于target的第1位来说,他往前0个字符和第0位往后0个字符相等,所以next[1]=0;
2.next[2]=0;
3.在这里插入图片描述
对于target的第3位来说,他往前1个字符和第0位往后1个字符相等,所以next[3]=1-1;这里需要说明一下,索引是从0开始的,(由于不相等我也记录为0,各位各自实现的实现可以区分开来,比如用-1代替不相等的)

最后得到next数组为[0,0,0,0,1,0];

六:赋上代码
这个和网上流程的不太相同,是按照我自己的理解实现的,是正确的不用怀疑,在lintCode上测试通过了的,?

public int[] getNext(String ps) {

    char[] p = ps.toCharArray();
    int[] next = new int[p.length];
    if(next.length > 0) {
         next[0] = 0;
    }
    int i = 1;
    int j = 0;
     while (i < p.length) {
     
      if (p[i] == p[j]) {
        next[i] = j;
        i++;
        j++;
      } else {

          j=0;
          next[i]=j;
          i++;
      }
     }
     return next;
  } 

另外附上source不变,更改target的索引来查找target在source中位置的代码

public int strStr(String source, String target) {
        // Write your code here‘
        
       char[] t = source.toCharArray();
  
       char[] p = target.toCharArray();
  
       int i = 0; // 主串的位置
 
       int j = 0; // 模式串的位置
 
      int[] next = getNext(target);
  
      while (i < t.length && j < p.length) {
  
      if (t[i] == p[j]) { // 当j为-1时,要移动的是i,当然j也要归0
  
            i++;
 
          j++;
 
        } else {
 
         if(j==0) {
             i++;
         }
         j = next[j]; // j回到指定位置
 
      }
    }
    if (j == p.length) {
 
        return i - j;
  
     } else {
  
       return -1;
  
      }
    }

七:完整解答

public class Solution {
    
   public int[] getNext(String ps) {

    char[] p = ps.toCharArray();
    int[] next = new int[p.length];

    if(next.length > 0) {
         next[0] = 0;
    }
    
    int i = 1;
    int j = 0;

   while (i < p.length) {
      if (p[i] == p[j]) {

        next[i] = j;
        i++;
        j++;
      } else {
      
          j=0;
          next[i]=j;
          i++;
      }
     }
     return next;
  } 
    /**
     * @param source: 
     * @param target: 
     * @return: return the index
     */
    public int strStr(String source, String target) {
        // Write your code here‘
        
       char[] t = source.toCharArray();
       char[] p = target.toCharArray();
  
       int i = 0; // 主串的位置
       int j = 0; // 模式串的位置
       int[] next = getNext(target);
  
       while (i < t.length && j < p.length) {
 
      if (t[i] == p[j]) { // 当j为-1时,要移动的是i,当然j也要归0
           i++;
          j++;
 
        } else {
 
         if(j==0) {
             i++;
         }
         j = next[j]; // j回到指定位置
      }
    }
    if (j == p.length) {
 
        return i - j;
     } else {
       return -1;
      }
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(代码)   项目:JavaScript 记忆游戏(代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值