KMP算法

简介

KMP算法是一种改进的字符串匹配算法,KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。

示例

比如:现有字符串 str1 = ‘ABABDABACDABABCABAB’, 字符串 str2 = ‘ABABCABAB’, 计算 str2 字符串在 str1 中出现的起始下标。

解法1:暴力匹配

使用暴力匹配

// 实现一个简单的字符串搜索算法(返回str2在str1中第一次出现的下标)
    public static int indexOf(String str1, String str2) {
        if (str1 == null || str2 == null || str2.length() > str1.length()) {
            return -1; // str2 不可能在 str1 中
        }

        for (int i = 0; i <= str1.length() - str2.length(); i++) {
            int j;
            for (j = 0; j < str2.length(); j++) {
                if (str1.charAt(i + j) != str2.charAt(j)) {
                    break; // 一旦发现字符不匹配,立即跳出内部循环
                }
            }
            if (j == str2.length()) {
                return i; // 找到str2在str1中的起始下标
            }
        }
        return -1; // 没有找到str2在str1中的匹配项
    }

    public static void main(String[] args) {
        String txt = "ABABDABACDABABCABAB";
        String pat = "ABABCABAB";
        System.out.println("Index: " + indexOf(txt, pat)); // 应输出 "Index: 10"
    }

结果:Index: 10
暴力匹配是使用双循环匹配,最大的问题是效率低下,实现简单,
问题:使用暴力匹配会发现重复匹配,比如 str2 匹配到下标4和str1 不匹配时,又会重str1的下标1 开始匹配。

解法2:KMP 算法

 /**
     * 计算匹配字符串的复用前后缀下标
     * 比如字符串:ABABCABAB
     * 那么返回值:[0,0,1,2,0,1,2,3,4]
     * 描述:这个下标数组的作用就是当匹配到指定下标失败的时候,根据下标的值进行向后匹配,而不用重复匹配,
     * 比如字符串匹配到下标为3失败时,则取数组下标为(3 - 1)的值1,然后从下标为1继续向后匹配
     * @param pattern
     * @return
     */
    public static int[] computePrefixFunction(String pattern) {
        int m = pattern.length();
        int[] longestPrefixSuffix = new int[m];
        int len = 0; // 长度为0的前后缀匹配的长度
        longestPrefixSuffix[0] = 0;

        for (int i = 1; i < m; i++) {
            while (len > 0 && pattern.charAt(len) != pattern.charAt(i)) {
                len = longestPrefixSuffix[len - 1];
            }

			// 如果值相同,标识可以复用,记录下标
            if (pattern.charAt(len) == pattern.charAt(i)) {
                len++;
            }
			// 将复用下标记录到对应的下标中
            longestPrefixSuffix[i] = len;
        }

        return longestPrefixSuffix;
    }

    public static int KMPSearch(String text, String pattern) {
        int n = text.length();
        int m = pattern.length();
        int[] lps = computePrefixFunction(pattern);
        System.out.println("lps:"+JSON.toJSONString(lps));
        int i = 0; // 文本字符串的索引,当前匹配到的索引
        int j = 0; // 模式字符串的索引,当前匹配到的索引

        while (i < n) {
        	// 根据下标判断值是否相同,相同的话,元数据下标和匹配数组下标自增
            if (pattern.charAt(j) == text.charAt(i)) {
                j++;
                i++;
            }
            // 如果当前已匹配下标等于字符串的下标表示匹配完了,直接返回
            if (j == m) {
                return i - j; // 找到模式在文本中的位置,返回位置的开始索引
            } else if (i < n && pattern.charAt(j) != text.charAt(i)) {
                // 不匹配的情况,说明下次循环不匹配,如果j!=0,就需要重新计算匹配的下标
                if (j != 0) {
                    j = lps[j - 1];
                } else {
                    // j=0,标识,匹配的字符串需要从头计算
                    i = i + 1;
                }
            }
        }
        return -1; // 如果模式不在文本中出现,返回-1
    }
 public static void main(String[] args) {
        String txt = "ABABDABACDABABCABAB";
        String pat = "ABABCABAB";
        System.out.println(pat);
        System.out.println("Index: " + KMPSearch(txt, pat)); // 应输出 "Index: 10"
    }

KMP算法主要是将匹配的字符串做复用下标处理,然后在匹配的时候,如果当前匹配不到,则根据复用下标处理。

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值