KMP算法 -解决匹配问题

KMP算法解决匹配问题,一个字符串是否包含另一个字符串。
【题目】
两个字符串str和match,长度为N和M,实现一个算法,如果字符串中包含match,则返回match在str中的开始位置,不含有则返回-1.
【举例】
str = “acbc” match = “bc” 返回2
str= “acbc” match = “bcc” 返回-1
【思路】
普通解法:
遍历str,看当前字符是否匹配match
eg:str= “aaaaaaaaaaab” match = “aaaab”
从str[0]开始匹配到str[4],str[4] 与match[4] =‘b’不一样,匹配失败
再从str[1]开始匹配…
直到str[7…11] 与,match匹配,返回11 ,复杂度为O(N*M)

KMP解法:
(1)生成match字符串的nextArr数组**(怎么确定数组的值)**
eg:match = “aaaab”
nextArr[4]应该为多少
match[4] = ’b‘它之前为“aaaa”
这个字符串的后缀子串和前缀子串最大匹配为“aaa”
后缀子串:match[1…3] ==“aaa”
前缀字串:match[0…2] ==“aaa”
所以,nextArr[4] = 3
eg:match = “abc1abc1”
nextArr[7] 为多少
match[7] ==‘1’ 它之前的字符串为“abc1abc”
即后缀子串和前缀子串最大匹配为abc
后缀子串:match[4…6] ==“abc”
前缀字串:match[0…2] == “abc”
这时不仅相等,而且是所有前缀和后缀可能性中最大的匹配
所以nextArr[7] = 3
(2)如何加速进行str和match匹配过程,(有了nextArr之后)
从str[i]开始匹配到str[j]和match[j-i]匹配失败
在这里插入图片描述
nextArr[j-i] 表示match[0,j-i-1]这段字符串前缀和后缀的最长匹配
在这里插入图片描述
所以下一次检查就可以直接让str[j]与match[k]匹配(而不是str[i+1])
在这里插入图片描述
代码实现

public int getIndexOf(String s,String m){
        if(s == null || m == null || m.length()<1 || s.length() < m.length()){
            return -1;
        }
        char[] ss = s.toCharArray();
        char[] ms = m.toCharArray();
        int si = 0;
        int mi = 0;
        int[] next = getIndexOf(ms);
        while (si < ss.length && mi < ms.length){
            if(ss[si] == ms[mi]){
                si++;
                mi++;
            }else if(next[mi] == -1){
                si++;
            }else {
                mi = next[mi];
            }
        }
        return mi == ms.length ? si - mi : -1;
    }

如何快速得到match字符串的nextArr数组
对于match[0],在它之前没有字符,所以nextArr[0]为-1
对于match[1],在它之前有match[0],所以nextArr[0]为0(nextArr数组的定义要求任何子串的后缀不能包括第一个字符match[0])
对于match[i]:
通过比较可知B字符前的字符串最长前缀与后缀匹配区域,
I区域为最长匹配前缀,K区域为最长匹配后缀,
比较C和B是否相等
如果相等,那么A字符之前的字符串的最长前缀和后缀匹配区域就可以确定,
前缀为I+C,后缀为K+B
即nextArr[i] = nextArr[i-1]+1
在这里插入图片描述
如果不相等,看字符C之前的前缀和后缀匹配情况,
m和n分别是C之前的字符串最长匹配的后缀和前缀区域,这时通过nextArr[cn]确定的,两个区域相等,m和m’区域也相等,接下来比较D和B是否相等即可
如果相等,前缀为n+D,后缀为m’+B,则令nextArr[i] = nextArr[cn]+1
如果不相等,则继续往前跳到D,只要有相等的情况,nextArr[i]的值就能确定。
在这里插入图片描述
如果跳到最左位置,即match[0]位置,此时nextArr[0] == -1,说明A之前的字符串不存在前缀和后缀匹配的情况,令nextArr[i] = 0
代码实现

public static int[] getNextArray(char[] ms){
        if(ms.length == 1) return new int[] {-1};
        int[] next = new int[ms.length];
        next[0] = -1;
        next[1] = 0;
        int pos = 2;
        int cn = 0;
        while (pos < next.length){
            if(ms[pos - 1] == ms[cn]){
                next[pos++] = ++cn;
            }else if(cn > 0){
                cn = next[cn];
            }else {
                next[pos++] = 0;
            }
        }
        return next;
    }

参考:《程序员代码面试指南:IT名企算法与数据结构题目最优解》

发布了110 篇原创文章 · 获赞 31 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39795049/article/details/96102418
今日推荐