KMP

10 篇文章 0 订阅

import java.util.Arrays;

/**
 * @program: sorttest
 * @description: KMP算法
 * @author: zhaozhenwei
 * @create: 2021-03-28 18:44
 **/
public class KMPAlgorithm {

    public static void main(String[] args) {
        String mainStr = "123124128903124124124567890378";
        String subStr =  "124124124";
        int[] nextVal = nextVal(subStr);
        System.out.println(Arrays.toString(nextVal));

        int startIndex = containers1(mainStr, subStr);
        System.out.println(startIndex);

        startIndex = containers2(mainStr, subStr);
        System.out.println(startIndex);
    }

    /**
     * 校验mainString中是否包含subString
     * @param mainString    主串
     * @param subString     字串
     * @return
     */
    public static int containers(String mainString, String subString) {
        // 主串、子串为空的时候返回false,表示不包含
        if (null == mainString || null == subString) {
            return -1;
        }
        return containers2(mainString, subString);
    }

    /**
     * KMP算法
     *  **目前只知道改怎么做,具体原理暂时无法说清**
     *  1、计算子串中每个下标前的集合中最大的相同的前缀和后缀的长度,放在临时数组中nextVal,该数组用于表示下次比较时从子串的那个下标开始比较
     *  2、对主串和字串进行比较,假如比较到主串下标A,子串下标B时,字符不一致时,停止比较,
     *  3、根据当前子串的下标B通过nextVal获取当前应当从子串的那个下标处开始比较
     *  4、主串则从之前元素不同的地方A进行比较,如果之前是主串和字串比较的第一个元素不同而停止比较的,则需要将A向后移一位,和字串的下标0进行比较
     * @param mainString
     * @param subString
     * @return
     */
    private static int containers2(String mainString, String subString) {
        int mainStrLength = mainString.length();
        int subStrLength = subString.length();
        if (mainStrLength < subStrLength) {
            return -1;
        }

        int[] nextVal = nextVal(subString);
        int subStartIndex = 0;
        for (int i = 0; i < mainStrLength - subStrLength; ) {
            for (; subStartIndex < subStrLength; subStartIndex++) {
                if (mainString.charAt(i) == subString.charAt(subStartIndex)) {
                    i++;
                } else {
                    break;
                }
            }
            // 当主串当前比较的第一个元素和子串第一个元素不相等时,将主串的位置向后移一位
            if (subStartIndex == 0) {
                i++;
            }
            if (subStartIndex < subStrLength) {
                subStartIndex = nextVal[subStartIndex];
            } else {
                return i - subStrLength;
            }
        }


        return -1;
    }

    /**
     * 查找字符串str中每个下标前的子串A中最长的前缀和后缀相等的字符长度
     *  要找的前缀和后缀的长度需要小于子串A的长度
     * @param str
     * @return
     */
    private static int[] nextVal(String str) {
        int strLen = str.length();
        int[] nextValArr = new int[strLen];
        for (int i = 1; i < strLen; i++) {
            int start = 0;
            int end = i - 1;
            for (int j = 0; j < end; j++) {
                for (int k = 0; k < j; k++) {
                    String prefix = str.substring(start, start+k+1);
                    String suffix = str.substring(end - k, end+1);
                    if (prefix.equals(suffix)) {
                        nextValArr[i] = k+1;
                    }
                }

            }
        }
        return nextValArr;
    }


    /**
     * 暴力方法
     *      通过对主串的下标依次增加,对主串的每个子串进行比较
     * @param mainString
     * @param subString
     * @return
     */
    private static int containers1(String mainString, String subString) {
        int mainStrLength = mainString.length();
        int subStrLength = subString.length();
        if (mainStrLength < subStrLength) {
            return -1;
        }

        // 从主串的第一个元素开始,截取和子串相同长度的子串进行比较
        //  从下标0为开始,比较截取的子串和要比较的字串
        //  相同的话下标各子加1,继续比较
        //  不同的时候,从主串的下一个下标截取子串,再次和传进来的子串进行比较
        for (int i = 0; i <= mainStrLength - subStrLength; i++) {
            int k = i;
            int l = 0;
            for (int j = 0; j < subStrLength; j++) {
                if (mainString.charAt(k) == subString.charAt(j)) {
                    k++;
                    l++;
                } else {
                    break;
                }
            }
            // 跳出循环时,如果比较的长度和要比较的子串的长度一致时,说明主串包含子串
            if (l == subStrLength) {
                return k - subStrLength;
            }
        }
        return -1;
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符串匹配算法,用于在一个字符串中查找另一个较短的模式串的出现位置。它的实现基于两个关键概念:部分匹配表和最大匹配前缀后缀数组(next数组)。通过构建next数组,KMP算法能够在失配时将模式串跳过一定长度,从而提高了匹配的效率。 在给定的引用内容中,有几个代码片段涉及到了使用Python实现KMP算法。这些代码分别是通过暴力搜索、利用next数组进行匹配以及计算next数组的实现。暴力搜索算法的时间复杂度为O(m*n),而KMP算法的时间复杂度为O(m+n),其中m为主串的长度,n为模式串的长度。 在KMP算法中,next数组记录了模式串中每个位置之前的最长公共前缀和最长公共后缀的长度。通过根据next数组的值来调整模式串的位置,KMP算法能够避免不必要的比较,从而提高匹配效率。 因此,Python中的KMP算法可以通过构建next数组来实现,在匹配过程中根据失配时的next值进行模式串的调整,直到找到匹配位置或匹配失败。这样可以在较短的时间内找到模式串在主串中的位置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [KMP算法(python)](https://download.csdn.net/download/weixin_38618540/14854290)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [KMP算法(Python)](https://blog.csdn.net/m0_52238102/article/details/115830347)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值