BmUtils

作者: kevinfuture | 来源:发表于2018-09-14 12:00 被阅读0次

    package com.kevinfuture.opt.utils;

    /**
     * BM算法
     * @author kevin
     * **/
    
    public class BmUtils {
    
        public static void main(String[] args) {
            String test = "3rfdfgs海1贼1王0";
            System.out.println(indeOf(test, "海134贼1王"));
        }
    
        public static String indeOf(String source, String target) {
    
            char[] sourceChars = source.toCharArray();
            char[] targetChars = target.toCharArray();
            
           if(sourceChars.length < targetChars.length){
                return "";
            }
    
            //源字符串移动下标
            int i = targetChars.length - 1;
            //目标模式串移动下标
            int j = targetChars.length - 1;
    
            /**
             * 当时设计不周全,没有考虑到边界问题
             * 新增一个变量,标记是否到了结尾
             * 如果达到结尾,再次不匹配的时候,即可直接跳出
             * **/
            boolean flagOver = false;
            while(i < sourceChars.length & j > -1){
                //若相等,则从后往前移动一位继续比较
                if(sourceChars[i] != targetChars[j]){
                    if(flagOver){
                        break;
                    }
    
                    /**
                     * 网上讲的内容虽然对,但是没那么复杂理解。简单来说,不管匹配不匹配,都将模式串右移
                     * 直到与模式串:
                     * 坏字符,最靠左的一个字符,匹配,不匹配则继续右移一位;
                     * 好后缀,最靠左的一个字符,匹配/部分匹配/不匹配;
                     * PS:变相来看 =》 判断模式串当前匹配位置i 左侧与右侧的长度 =》
                     * Math.max( 左侧与i值的长度; 模式串匹配,与右侧i+1位置的值匹配否,若不匹配则继续i++验证匹配否)
                     */
                    int m = getBmBadChar(sourceChars[i], targetChars, j);
                    int n = getBmGoodSuffix(sourceChars, targetChars, i, j);
    
                    int len = Math.max(m,n);
                    i = i + len;
                    i = Math.min(i, sourceChars.length - 1);
                    j = targetChars.length - 1;
                    if(i + 1 == sourceChars.length){
                        flagOver = true;
                    }
                }else {
                    i--;
                    j--;
                }
            }
            System.out.println( j + "   " + i);
            char[] chars = new char[i - j + 1];
            int y = 0;
    
            for(int x = i + 1; x < i + j; x++ ){
                chars[y++] = targetChars[x];
            }
            return String.valueOf(chars);
        }
    
        /**
         * 粘自阮一峰老师的博客:
             (1)"好后缀"的位置以最后一个字符为准。假定"ABCDEF"的"EF"是好后缀,则它的位置以"F"为准,即5(从0开始计算)。
           (2)如果"好后缀"在搜索词中只出现一次,则它的上一次出现位置为 -1。比如,"EF"在"ABCDEF"之中只出现一次,则它的上一次出现位置为-1(即未出现)。
           (3)如果"好后缀"有多个,则除了最长的那个"好后缀",其他"好后缀"的上一次出现位置必须在头部。比如,假定"BABCDAB"的"好后缀"是"DAB"、"AB"、"B",请问这时"好后缀"的上一次出现位置是什么?
                回答是,此时采用的好后缀是"B",它的上一次出现位置是头部,即第0位。这个规则也可以这样表达:如果最长的那个"好后缀"只出现一次,则可以把搜索词改写成如下形式进行位置计算"(DA)BABCDAB",
                即虚拟加入最前面的"DA"。
         * 好后缀
         * n:模式串索引位置
         * i:好后缀索引位置
         * **/
        private static int getBmGoodSuffix(char[] sourceChars, char[] targetChars, int i, int j){
            int n = 0;
            for(; n < j; n++){
                while(i < sourceChars.length){
                    if(targetChars[n] == sourceChars[i++]){
                        n++;
                    }else{
                        n = 0;
                    }
                }
            }
            return j - n;
        }
        /**
         * 坏字符
         * @return 返回的是匹配值对应的下标序号
         * **/
        private static int getBmBadChar(char sChar, char[] targetChars, int j){
            int m = j;
            for(; m >= 0; m--){
                if(targetChars[m] == sChar){
                    return j - m;
                }
            }
            return j + 1;
        }
    }
    

    PS:尚有些问题,需要调整;坏字符、好后缀获取的没有问题

    相关文章

      网友评论

          本文标题:BmUtils

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