• Leetcode28--->字符串的匹配(KMP)


    题目: 题目的本质是给定两个字符串str1,str2,求str1中的str2串开始的地方,即字符串的匹配,KMP算法

    思路:时间复杂度为O(m + n),空间复杂度为O(n),原串的长度为m,子串的长度为n

    KMP算法的本质是根据子串的next值求解的,所以首先讲解next值得求法:

    字串的Next值的求解方法:

    next[i]的含义是:以i-1位置结尾的字符串与以0位置开始的字符串的最长匹配

    1. 创建一个与子串大小相同长度的int型数组next

    2. next值中的next[0] = -1, next[1] = 0,这是一定的。下来求2 - 串尾的每个位置的next值。假设此时求next[i]的值:由于next[i]的含义是以i-1位置结尾的字符串与以0位置开始的字符串的最长匹配,而此时我们已经求除了i-1位置的next值,next[i - 1]含义是以i-2位置结尾的字符串与以0位置开始的字符串的最长匹配。我们使用cn表示与以i-2结尾的字符串的匹配长度所以next[i - 1] = cn

    a)如果i-1位置的值等于cn+ 1位置的值,则next[i] = next[i -1] + 1;由于next[i - 1]匹配的是0~cn和某个地方到i - 2, 因此如果cn + 1位置的值和i -1位置的值相等,则next[i] = cn + 1;

    b)  否则 ,判断next[i - 1]的值是不是大于0,大于0表示前面有某个位置还有匹配的可能性,即next值回退过程,cn =  next[cn]

    c) 否则,表示cn = 0,即回退到第一个位置了,则next[i] = 0;

    如上图所示: 我们来回顾一下next值的定义:next[i] = 以i-1位置结尾的字符串与以0位置开始的字符串的最长匹配

    假设此时需要求i位置的next值,而我们已经知道next[i-1]的值,是从[0,z]和[i-2 - z, i-2]的匹配,长度为z,即next[i -1] = z;此时:

    1)如果z的下一个位置w的值和i-1的值相等,则就有了[0, z + 1] 和[i-2-z, i - 1]的匹配,该匹配就是next[i] 的值;

    2)如果w = z + 1位置的值不等于i-1位置的值,则表示匹配的长度会比z短,而next[i - 1] = z, 此时我们要求的是next[z]的值:假设next[z] 的匹配为[0, x]和[z - 1- x, z-1], 同理,若y = x + 1位置的值与i - 1位置的值相等,则next[i] = next[z] + 1,若y位置的值与i-1位置的值不相等,则继续向前回退,直到next[i] = 0;

    证明过程:

    此时next[i] = [0, x]长度,next[i]的长度为什么不可能长于x?

    [0, z] = [i -2 - z, i - 2], [0, x] = [z - 1 - x, z - 1], 由于[0, x] ∈[0, z], 因此[0, x]∈[i -2 - z, i - 2],再回想一下next[i]的定义,因此只要x+ 1位置的值与i-1位置的值相等,则可以计算出next[i]的值;

    我们此时假设next[i]的长度为[0, q]的匹配,q > z + 1,则 i-1和q位置,i-2和q- 1位置的值.....都是相等的,那么next[i -1] 的值就为[0, q]的匹配,q > z , 显然与”最长匹配原则“不一致;

    我们再假设next[i] 的长度为[0, x]的匹配,z > q > x + 1, 则 i-1和q位置,i-2和q- 1位置的值.....都是相等的,那么next[i - 1]的值就是[0, q]的匹配,而q < z,因此与”最长匹配不相等“

    KMP的匹配过程:

    1. 从头开始匹配,如果相等,则子串和原串都继续向后

    2.如果在子串的某个位置i不相等,则表示i-1前面的都已经匹配上了,所以子串和原串都不要回退,由于next[i] 表示的是i-1位置结尾的字符串和以0位置开始的字符串的最长匹配,所以,如果next[i] = -1,则表示原串与子串的第一个字符否没有匹配,则原串位置向后移动,否则 只需要从子串的next[i]位置与原串继续比较即可。

    假设此时比较到子串的i位置,对应主串的s+ 1位置不匹配,表明[t,s]和[0, i -1]是匹配的,则根据next[i]的含义,可以得出子串中[0, x1]与主串[s1,s]是匹配的,因此下一次只需要从字串的x1+1位置和s+ 1位置进行比较即可;

    代码如下:

     1 public class Solution {
     2     // KMP算法
     3     public int strStr(String haystack, String needle) {
     4         if(haystack == null || needle == null || haystack.length() < needle.length())
     5             return -1;
     6         if(haystack.length() == 0 || needle.length() == 0)
     7             return 0;
     8         int[] next = calNext(needle);
     9         int hlen = haystack.length();
    10         int nlen = needle.length();
    11         int hindex = 0;
    12         int nindex = 0;
    13         while(hindex < hlen && nindex < nlen)
    14         {
    15             if(haystack.charAt(hindex) == needle.charAt(nindex)) // 从头开始,若匹配就一直继续比较
    16             {
    17                 hindex ++;
    18                 nindex ++;
    19             }
    20             else if(next[nindex] == -1)  // 表示与子串的第一个字符就没有匹配上,则主串自己向后移动
    21             {
    22                 hindex ++;
    23             }
    24             else   // 直到nindex - 1都匹配上了,所以子串不需要从头继续,只需要从next[nindex]位继续匹配即可
    25             {
    26                 nindex = next[nindex];
    27             }
    28         }
    29         return nindex == nlen ? hindex - nindex : -1; // 如果匹配到子串的结尾,则返回此时主串与子串的位置差,即为开始匹配的地方
    30     }
    31     public int[] calNext(String needle)
    32     {
    33         if(needle.length() == 1)
    34             return new int[]{-1};
    35         int[] next = new int[needle.length()];
    36         next[0] = -1;
    37         next[1] = 0;
    38         int cn = 0;
    39         int pos = 2;
    40         while(pos < next.length)
    41         {
    42             if(needle.charAt(pos -  1) == needle.charAt(cn))
    43                 next[pos ++] = ++cn;
    44             else if(cn > 0)  // 回退
    45                 cn = next[cn];
    46             else
    47                 next[pos ++] = 0;
    48         }
    49         return next;
    50     }
    51 }
  • 相关阅读:
    JavaScript 实现深度拷贝
    JacaScript arguments
    EMACS 使用入门
    ubuntu 14.04 nginx + mysql + php源码安装
    c语言 头文件
    程序员技术练级攻略
    if和switch的选择
    .htaccess (分布式配置文件)
    yii2 windows 安装过程
    Js 冒泡事件阻止
  • 原文地址:https://www.cnblogs.com/leavescy/p/5884306.html
Copyright © 2020-2023  润新知