数据结构-String字符串匹配(BM,KMP)

KMP

参考:https://baijiahao.baidu.com/s?id=1659735837100760934&wfr=spider&for=pc

// KMP
    public static int kmp(String str, String pattern) {
        // 预处理,生成next数组
        int[] next = getNexts(pattern);
        int j = 0;
        // 主循环,遍历主串字符
        for (int i = 0; i < str.length(); i++) {
            while (j > 0 && str.charAt(i) != pattern.charAt(j)) {
                //遇到坏字符时,查询next数组并改变模式串的起点
                j = next[j];
            }
            if (str.charAt(i) == pattern.charAt(j)) {
                j++;
            }
            if (j == pattern.length()) {
                //匹配成功,返回下标
                return i - pattern.length() + 1;
            }
        }
        return -1;
    }

    // 生成Next数组
    private static int[] getNexts(String pattern) {
        int[] next = new int[pattern.length()];
        int j = 0;
        for (int i = 2; i < pattern.length(); i++) {
            while (j != 0 && pattern.charAt(j) != pattern.charAt(i - 1)) {
                //从next[i+1]的求解回溯到next[j]
                j = next[j];
            }
            if (pattern.charAt(j) == pattern.charAt(i - 1)) {
                j++;
            }
            next[i] = j;
        }
        return next;
    }

String str = “ATGTGAGCTGGTGTGTGCFAA”;
String pattern = “GTGTGCF”;
int index = stringMatch.kmp(str, pattern);
System.out.println(“首次出现位置:” + index);
首次出现位置:12

BM

参考:https://blog.csdn.net/baidu_39502694/article/details/106475463

// BM算法匹配字符串,匹配成功返回P在S中的首字符下标,匹配失败返回-1
    public int bmMatch(String source, String pattern) {
        char[] src = source.toCharArray();
        char[] ptn = pattern.toCharArray();
        int sLen = src.length;
        int pLen = ptn.length;

        if (pLen == 0) {
            return 0;
        }
        if (sLen < pLen) {
            return -1;
        }
        int[] BC = buildBadCharacter(ptn);
        int[] GS = buildGoodSuffix(ptn);

        for (int i = pLen - 1; i < sLen; ) {
            int j = pLen - 1;
            for (; src[i] == ptn[j]; i--, j--) {
                if (j == 0) {
                    return i;
                }
            }

            // 每次后移“坏字符规则”和“好后缀规则”两者的较大值
            // 注意此时i(坏字符)已经向前移动,所以并非真正意义上的规则
            i += Math.max(BC[src[i]], GS[pLen - 1 - j]);
        }

        return -1;
    }

    // 坏字符规则表
    public static int[] buildBadCharacter(char[] pattern) {
        int pLen = pattern.length;
        final int CHARACTER_SIZE = 256;
        int[] BC = new int[CHARACTER_SIZE];
        Arrays.fill(BC, pLen);
        for (int i = 0; i < pLen - 1; i++) {
            int ascii = pattern[i];
            BC[ascii] = pLen - 1 - i;
        }
        return BC;
    }

    // 非真正意义上的好字符规则表,后移位数还加上了当前好后缀的最大长度
    private static int[] buildGoodSuffix(char[] pattern) {
        int pLen = pattern.length;
        int[] GS = new int[pLen]; // 记录好后缀出现时后移位数
        int lastPrefixPos = pLen; // 好后缀的首字符位置

        for (int i = pLen - 1; i >= 0; i--) {
            // i+1是主串begin(含)之后的子串是否匹配模式串的前缀
            if (isPrefix(pattern, i + 1)) {
                lastPrefixPos = i + 1;
            }
            GS[pLen - 1 - i] = lastPrefixPos + pLen - 1 - i;
        }
        // 上面在比较好后缀时,是从模式串的首字符开始的,但实际上好后缀可能出现在模式串中间。
        // 比如模式串EXAMPXA,假设主串指针在比较P时发现是坏字符,那么XA就是好后缀,
        // 虽然它的首字符X与模式串的首字符E并不相等。此时suffixLen=2表示将主串指针后移至模式串末尾,
        // pLen-1-i=4表示真正的好字符规则,同样主串指针后移,使得模式串前面的XA对齐主串的XA
        for (int i = 0; i < pLen - 1; i++) {
            int suffixLen = suffixLength(pattern, i);
            GS[suffixLen] = pLen - 1 - i + suffixLen;
        }

        return GS;
    }

    // 判断是否是好后缀,即模式串begin(含)之后的子串是否匹配模式串的前缀
    private static boolean isPrefix(char[] pattern, int begin) {
        for (int i = begin, j = 0; i < pattern.length; i++, j++) {
            if (pattern[i] != pattern[j]) {
                return false;
            }
        }
        return true;
    }

    // 返回模式串中以pattern[begin](含)结尾的后缀子串的最大长度
    private static int suffixLength(char[] pattern, int begin) {
        int suffixLen = 0;

        int i = begin;
        int j = pattern.length - 1;
        while (i >= 0 && pattern[i] == pattern[j]) {
            suffixLen++;
            i--;
            j--;
        }

        return suffixLen;
    }

StringMatch stringMatch = new StringMatch();
int i = stringMatch.bmMatch(“HERE IS A SIMPLE EXAMPLE”, “EXAMPLE”);
System.out.println(“结果:”+i);
结果:17

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值