BM算法(字符串模式匹配)

参考的该篇文章:字符串匹配算法(BM)
https://blog.csdn.net/qq_21201267/article/details/92799488
详细推倒过程参考上面的链接,以下仅是个人笔记

1求坏字符

    //坏字符规则:获得坏字符数组
    //该int[]浪费空间,可以优化,badChars[c-‘a’] = i;
    public static void getBc(String pat, int[] badChars) {
        int len = pat.length();
        for (int i = 0; i < size; i++) {
            badChars[i]=-1;
        }
        for (int i = 0; i < len; i++) {
            char c = pat.charAt(i);
            badChars[c] = i;
        }
    }

2仅使用坏字符规则实现的BM

    //仅使用坏字符规则实现的BM
    public static int StrBm(String tar, String pat) {
        int len1 = tar.length();
        int len2 = pat.length();
        int[] badChars = new int[size];
        getBc(pat, badChars);
        int i = 0;
        int j;
        while (i <= len1 - len2) {
            for (j = len2 - 1; j >= 0; j--) {
                if (tar.charAt(i + j) != pat.charAt(j)) {
                    break;
                }
            }
            //匹配成功,直接返回
            if (j < 0) {
                return i;
            }
            i = i + j - badChars[tar.charAt(i + j)];
        }
        return -1;
    }

3使用HashMap存储坏字符

    //使用HashMap存储每个坏字符在模式串中的位置,节省坏字符数组大小
    public static void getBc1(String pat, Map<Character,Integer> badChars) {
        int len = pat.length();
        for (int i = 0; i < len; i++) {
            badChars.put(pat.charAt(i), i);
        }
    }

    //仅使用坏字符规则实现的BM
    public static int StrBm1(String tar, String pat) {
        int len1 = tar.length();
        int len2 = pat.length();
        Map<Character,Integer> badChars = new HashMap<>();
        getBc1(pat, badChars);
        int i = 0;
        int j;
        while (i <= len1 - len2) {
            for (j = len2 - 1; j >= 0; j--) {
                if (tar.charAt(i + j) != pat.charAt(j)) {
                    break;
                }
            }
            if (j < 0) {
                return i;
            }
            int move = j - (null == badChars.get(tar.charAt(i + j)) ? -1 : badChars.get(tar.charAt(i + j)));
            i = i + move;
        }
        return -1;
    }

4求好后缀

    //好后缀规则
    public static void getGs(String pat, int[] suffix, boolean[] prefix) {
        int len = pat.length();
        for (int i = 0; i < len; i++) {
            suffix[i] = -1;
            prefix[i] = false;
        }

        int i;//依次从前往后遍历模式串
        int j;//
        int k;
        for (i=0;i<=len-2;i++){
            //每次j和i为模式串前缀的终点,从后开始往前与后缀匹配,所以j--;
            j=i;
            //记录前缀子串和后缀子串共有的长度
            k=0;
            while (j>=0 &&pat.charAt(j)==pat.charAt(len-1-k)){
                j--;
                k++;
                suffix[k]=j+1;
            }
            //查找到模式串的头部了
            if(j<0){
                prefix[k]=true;
            }
        }
    }

5好后缀移动位数(三种情况)

    public static int getBsMove(int j, int len, int[] suffix, boolean[] prefix){
        //好后缀长度
        int k = len - 1 - j;
        //第一种情况,好后缀数组里面存在匹配的字符串
        if (suffix[k] != -1) {
            return j+1 -suffix[k];
        }
        //第二种情况,好后缀的后缀子串和模式串的前缀子串有相等的
        for (int r = j + 2; r < len; r++) {
            if(prefix[len-r]==true){
                return r;
            }
        }
        //第三种情况,都没有匹配的,直接移动模式串长度
        return len;
    }

6使用坏字符规则和好后缀规则实现的BM

    //使用坏字符规则和好后缀规则实现的BM
    public static int StrBm2(String tar, String pat) {
        int len1 = tar.length();
        int len2 = pat.length();
        //获得坏字符数组
        Map<Character, Integer> badChars = new HashMap<>();
        getBc1(pat, badChars);

        //获得好后缀数组
        int[] suffix = new int[len2];
        boolean[] prefix = new boolean[len2];
        getGs(pat, suffix, prefix);

        int move1 = 0;//使用坏字符规则移动的个数
        int move2 = 0;//使用好后缀规则移动的个数
        int i = 0;
        int j;
        while (i <= len1 - len2) {
            for (j = len2 - 1; j >= 0; j--) {
                if (tar.charAt(i + j) != pat.charAt(j)) {
                    break;
                }
            }
            //匹配成功
            if (j < 0) {
                return i;
            }
            move1 = j - (null == badChars.get(tar.charAt(i + j)) ? -1 : badChars.get(tar.charAt(i + j)));

            move2 = 0;//重要,这个不能忘,否则下一步出错
            //说明存在好后缀
            if (j < len2 - 1) {
                move2 = getBsMove(j, len2, suffix, prefix);
            }
            i = i + Math.max(move1, move2);
        }
        return -1;
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值