美文网首页
在母串内查找子串 KMP 算法

在母串内查找子串 KMP 算法

作者: 是瑞瀛呀 | 来源:发表于2020-05-24 01:56 被阅读0次

之前了解了下这个算法,实现了下,有问题欢迎指教

package org.huangry.colorful.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

/**
 * ClassName: KMPUtil
 *
 * @author huangruiying
 * @version 1.0
 */
public class KMPUtil {

    private Logger logger = LoggerFactory.getLogger(KMPUtil.class);

    //计算后的序列
    private static int[] substring_sequence_arr;

    private String parentStr = "";
    private String childStr = "";

    public KMPUtil(String parentStr, String childStr){
        this.parentStr = parentStr;
        this.childStr = childStr;
        //处理子串:生成子串序列到substring_sequence_arr
        generate_substring_sequence(childStr);
        logger.info(">>> KMP init success");
        logger.info(">>> substr_seq_array {}",Arrays.toString(substring_sequence_arr));
    }

    /**
     * 查询母串内是否包含子串
     * 然后返回索引
     *  不包含时 索引为 -1
     *  包含时 索引为第一次出现的位置
     */
    public int start(){
        //通过KMP查询
        int index = search(parentStr,childStr);
        logger.info("子串在目标字符串的索引: {}", index);
        return index;
    }

    /**
     * 获取母串内包含子串的个数
     * @return
     */
    public int getCount(){
        return count(parentStr,childStr);
    }

    /**
     * KMP查询
     * @author huangruiying
     * @param target 目标字符串
     * @param substring 待查询子串
     * @return 查找到的子串在目标字符串中的起始索引
     */
    private int search(final String target, final String substring) {

        final char[] target_arr = target.toCharArray();
        final char[] substring_arr = substring.toCharArray();
        //初始化游标 i:target游标 j:子串游标
        int i=0,j=0;

        //边界
        while (i < target_arr.length){
            char target_val = target_arr[i];
            char substring_val = substring_arr[j];
            if(target_val == substring_val){
                //跳出条件 (-1 : 长度跟索引比较,所以要-1)
                if(j == (substring.length()-1)){
                    /**
                     * 返回起始索引
                     * target&index:sssa&0123
                     * substr&index:sa&01
                     * 返回 (3-1)= 2 , 2为substring sa第一字在target中出现的索引位置。
                     */
                    return i-j;
                }
                i++;
                j++;
            }else{
                int before_j = j - 1;
                //子串边界
                if(before_j < 0){
                    j = 0;
                }else{
                    j = substring_sequence_arr[before_j];
                }
                //未寻找到时的跳出条件
                if(i == (target.length()-1)){
                    return -1;
                }
            }
        }

        return -1;
    }

    private int count(final String target, final String substring) {

        int count = 0;// 计数 target 内包含多少个 substring

        final char[] target_arr = target.toCharArray();
        final char[] substring_arr = substring.toCharArray();
        //初始化游标 i:target游标 j:子串游标
        int i=0,j=0;

        //边界
        while (i < target_arr.length){
            char target_val = target_arr[i];
            char substring_val = substring_arr[j];
            if(target_val == substring_val){
                if(j == (substring.length()-1)){
                    count ++ ;
                    i ++ ;
                    j = 0;
                    continue;
                }
                i++;
                j++;
            }else{
                int before_j = j - 1;
                //子串边界
                if(before_j < 0){
                    j = 0;
                }else{
                    j = substring_sequence_arr[before_j];
                }
                //未寻找到时的跳出条件
                if(i == (target.length()-1)){
                    return count;
                }
                i ++ ;
            }
        }
        return count;
    }

    /**
     * 生成子串序列
     * 子串:abcdabca
     * 序列:00001231
     * 规则:使用i,j两游标,
     * 初始化变量i=0,j=1
     * 初始化序列数组 0 0 0 0 0 0 0 0
     * 对比i与j所在索引处的数组值是否相等
     * 若相等,那么j处序列数组值为i+1(索引+1) ,然后i,j分别向后移动一位
     * 若不相等,查看序列数组内当前i-1位置的值(索引),并将该值赋值给当前变量i 结束本次循环(注意i的边界情况)
     * @author huangruiying
     * @param substring 子串
     */
    private void generate_substring_sequence(String substring){
        substring_sequence_arr = new int[substring.length()];
        char[] substring_arr = substring.toCharArray();
        //游标
        int i=0,j=1;
        while (j<substring_arr.length){
            char iChar = substring_arr[i];
            char jChar = substring_arr[j];
            if(iChar == jChar){
                substring_sequence_arr[j] = i+1;
                j++;
                i++;
            }else{
                int before_i = i-1;
                //边界
                if(before_i < 0){
                    substring_sequence_arr[j] = 0;
                    j++;
                }else{
                    //通过序列内当前i的前一个值,改变i游标
                    i = KMPUtil.substring_sequence_arr[before_i];
                }
            }
        }
    }


}



相关文章

  • 在母串内查找子串 KMP 算法

    之前了解了下这个算法,实现了下,有问题欢迎指教

  • 字符串匹配KMP算法

    假设我们的字符串母串是,子串是,我们想找到子串在母串中出现的位置并统计总的出现次数,可以使用KMP算法。KMP算法...

  • KMP算法文章合集

    字符串的查找:朴素查找算法和KMP算法 暴力匹配算法与KMP算法(串的匹配) 字符串查找算法BF和KMP 字符串匹...

  • 数据结构之kmp算法

    Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串...

  • 算法(2)KMP算法

    1.0 问题描述 实现KMP算法查找字符串。 2.0 问题分析 “KMP算法”是对字符串查找“简单算法”的优化。 ...

  • JavaScript 二分查找 & KMP 算法

    KMP 查找 Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串 str1...

  • 子字符串查找(1)

    一、定义 本文主要介绍子字符串查找的各类常用算法,如朴素匹配算法(暴力查找)、KMP算法、BM算法等。各类匹配算法...

  • KMP算法——寻找子串位置

    KMP算法——寻找子串位置 1、KMP算法简介: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J....

  • 分享几道常见字符串算法题

    1. KMP 算法 谈到字符串问题,不得不提的就是 KMP 算法,它是用来解决字符串查找的问题,可以在一个字符串(...

  • KMP算法

    KMP算法用于子字符串查找(匹配)。 KMP是三个科学家[Knuth-Morris-Pratt]发明的,旨在对暴力...

网友评论

      本文标题:在母串内查找子串 KMP 算法

      本文链接:https://www.haomeiwen.com/subject/qxzrahtx.html