字符串模式匹配(朴素模式匹配、KMP模式匹配)

1.朴素模式匹配(暴力匹配)

1.1 实现思想

  • 对主串 S 和模式串 T 分别设置指针 i 和 j ,假设字符串下标从 0 开始
  • 初始时 i 和 j 分别指向每个串的第 0 个位置。在第 n 趟匹配开始时,i 指向主串 S 中的第 n-1 个位置,j 指向模式串T的第0个位置,然后逐个向后比较。
  • 若 T 中的每一个字符都与 S 中的字符相等,则称匹配成功,否则,当遇到某个字符不相等时,i 重新指向 S 的第 n 个位置,j 重新指向 T 的第 0 个位置,继续进行第 n+1 趟匹配。
  • 时间复杂度为 O(n*m),其中 n 和 m 分别为主串和模式串的长度。

1.2 具体代码实现

public class ViolenceMatch {

    public static int violenceMatch(String str1,String str2){

        char[] s1=str1.toCharArray();
        char[] s2=str2.toCharArray();

        int s1Len=s1.length;
        int s2Len=s2.length;

        int i=0;
        int j=0;

        while(i<s1Len&&j<s2Len){
            if(s1[i]==s2[j]){
                i++;
                j++;
            }else{
                i=i-j+1;
                j=0;
            }
        }

        if(j==s2Len){
            return i-j;
        }else{
            return -1;
        }
    }

    public static void main(String[] args) {

        String str1="java数据结构学习";
        String str2="学习";
        int index=violenceMatch(str1,str2);
        System.out.println(index);

    }
}

2.KMP模式匹配

2.1介绍

  •  kmp是一个解决如果模式串是在文本出现过,找到它最早出现位置的算法
  • KMP算法就是利用之前判断过的信息,通过一个next数组,保存模式串中前后最长公共子序列的长度,每次回溯时,通过next数组找到前面匹配过的位置,省去了大量的计算时间。

2.2.部分匹配表的产生

  • 部分匹配的实质就是:有时候字符串的头部和尾部会重复。比如“ABCDAB”之中,它的部分匹配值就是2(即'AB"的长度)。搜索词移动的时候,第一个“AB”向后移动4位(字符串长度-部分匹配值),就可以来到第二个“AB”的位置。
  • 这样i不用回溯,j跳到前2个位置,继续匹配的过程

               

2.3代码实现

public class KmpMatch {

//遍历
   /**
     * @param str1  源字符串
     * @param str2  子串
     * @param next   部分匹配表
     * @return  如果是-1就是没有匹配到,否则返回第一个匹配的位置
     */
    public static int kmpSearch(String str1,String str2,int[] next){
        for(int i=0,j=0;i<str1.length();i++){

            while(j>0&&str1.charAt(i)!=str2.charAt(j)){
                j=next[j-1];
            }
           if(str1.charAt(i)==str2.charAt(j)){
               j++;
           }
           //找到了匹配子串的部分
           if(j==str2.length()){
               return i-j+1;
           }
        }
        return -1;
    }

   //1.构建子串的部分匹配值表
    public static int[] keepNext(String dest){
        //创建一个next数组保存部分匹配值
        int[] next=new int[dest.length()];
        next[0]=0;//如果它的长度为1,部分匹配值就是0
        for(int i=1,j=0;i<dest.length();i++)
        {
            while (j>0&&dest.charAt(i)!=dest.charAt(j)){
                j=next[j-1];
            }
            if(dest.charAt(i)==dest.charAt(j)){
                j++;
            }
            next[i]=j;
        }
        return next;
    }

    public static void main(String[] args) {
        String str1="BBC ABCDAB ABCDABCDABDE";
        String str2="ABCDABD";

        int[] next=keepNext(str2);
        System.out.println("next="+ Arrays.toString(next));

        int index= kmpSearch(str1,str2,next);
        System.out.println("index="+index);
    }
}

参考资料:尚硅谷Java数据结构和算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值