Day 15 KMP算法

import java.util.Arrays;

public class KMPTest {
    public static void main(String[] args) {
        //源串
        String x = "BBC ABCDAB ABCDABCDABDE";
        //目标串
        String z = "ABCDABD";
//        int []table = getTable(z);
//        System.out.println(Arrays.toString(table));
        int s = KMP(x,z);
        System.out.println(s);
    }
    //kmp搜索
    public static int KMP(String a,String b){

        int []c = getTable(b);//获取目标串的部分匹配表
        //i代表源串的当前索引 j代表目标船的当前索引
        for (int i=0,j=0;i<a.length();i++){
            //如果当前目标串 与 源串前面已经有相同的字符了(当前源串对比的 是目标串第一个字符后面的字符时 不能是第一个字符)
            //并且当前源串索引对应值 不等于当前目标串索引对应值时 设置 j = c[j-1](部分匹配表[当前索引的前一个的(因为当前值不同 前一个值相同)部分匹配值])
            //如果相同那么j++ (i在for中本来就是每轮+1)对比下一位 如果对比的目标串的索引已经超出了目标串 那么代表已经找到目标了
            //如果值不同 且j=0 那么什么都不触发 进下次for循环i++ 在比
            while (j>0&&a.charAt(i)!=b.charAt(j)){
                j = c[j-1];
            }
            if (a.charAt(i) ==  b.charAt(j)){
                j++;
            }
            //如果只需要找一个目标那么这样返回 如果需要找多个目标 那么当此条件达成时重置j = j-1的部分匹配值(因为此时j已经超出了)
            if (j == b.length()){
                return i-j+1;
            }
        }
        return -1;
    }
    //获取部分匹配表
    public static int[] getTable(String x){
        //创建部分匹配表
        int []s = new int[x.length()];
        //因为当串的长度为1时 根本没有前后缀 所以他的部分匹配值必定未定
        s[0] = 0;
        //i代表当前串的最后一个元素 也就是后缀的最后一个
        // j代表当前 后缀的最后一个也就是i  应该和前缀的第几位比
        for (int i=1,j=0;i<x.length();i++){
            while (j>0 && x.charAt(i) != x.charAt(j)){
                j = s[j-1];
            }
            //对比当前 i所对应的元素和j所对应的元素 如果相同 那么j++ 并设置部分匹配表当前字符长度
            // (比如完整串为: ABCDABD时 现在i为4 串为:ABCDA(索引从0开始 i代表后缀的索引)
            // 而i代表的是后缀j代表的是前缀  这时 i("A"BCDA)和j(ABCD"A")比较 发现他们相同 于是j++
            // 再设置部分匹配表中i位置(也就是从头到这个字符 这整个字符的部分匹配值为1)的值为j(1)
            // 因为前面也在这样对比但是前面 i与j对应索引的值从未相同 所以j为1  按现在的情况进入下次for循环
            // 此时i=5  j=1  也就是A "B(j)" CDA "B(i)" 中 这两个值比较 这是因为当前i和j的前一个元素已经相同了
            // 这时我们发现当前ij也是相同的 那么j再次++  设置当前i(也就是上一个i的后面)索引的部分匹配表的值为j(2)
            // 此时再向后比 ABCDABD i=6 j=2 也就是AB "C(j)" DAB"D(i)" 发现他们不相同并且此时j>0(意思就是在尝试延长上个匹配串的长度)
            // 于是进入while循环 并设置 j = 0(部分匹配表[j-1](这个[]中的值代表当前索引2-1的部分匹配值)) j=0退出while循环
            // 再次判断ij对应的值 i=6 j=0)
            // 时的字符匹配值
            //j++以为
            if (x.charAt(i) == x.charAt(j)){
                j++;
            }
            s[i] = j;
        }
        return s;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值