字符串模式匹配:BF算法和RK算法

本文探讨了两种字符串匹配算法:BF算法(Brute Force)和RK算法。BF算法通过依次比较主串的子串与模式串,最坏情况下的时间复杂度为O(n*m),但因其简单易实现而常用。RK算法利用哈希函数加速比较过程,通过比较子串和模式串的哈希值来判断匹配性,提高了效率。
摘要由CSDN通过智能技术生成
  BF算法(暴力匹配算法,也叫朴素匹配算法).性能不是很高。

       我们在主串中,检查起始位置分别是0.1.2…n-m且长度为n-m+1个子串,看有没有跟模式串匹配的。(在A中查找B,A就是主串,B就是模式串,且A>B)。最坏的时间复杂度为O(n*m),
       但是实际上,这也是常用的,1.模式串和主串的长度都不会太长,2.算法思想简单,代码实现简单。

package jike;

public class BF {
    public static int BF(char[] str,char[] sub){
        int i=0,j=0;
        while(j<sub.length && i < str.length){
            if(str[i] == sub[j]){
                i++;j++;
            }
            else {
                i = i-j+1;
                j = 0;
            }
        }
        if(j == sub.length){
            return i-j;
        }
        else {
            return -1;
        }
    }
    public static void main(String[] args) {
        String str = "abcababcabc";
        String sub = "abcabc";
        char[] ch1 = str.toCharArray();
        char[] ch2 = sub.toCharArray();
        int index = BF(ch1,ch2);
        System.out.println("输出主串str:"+str);
        System.out.println("输出子串sub:"+sub);
        System.out.println("已找到,对应的主串下标为:"+index);
    }
}

RK算法,RK全称是(Rabin-Karp)算法。

       RK 算法的思路是这样的:我们通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了(这里先不考虑哈希冲突的问题,后面我们会讲到)。因为哈希值是一个数字,数字之间比较是否相等是非常快速的,所以模式串和子串比较的效率就提高了。

package jike;

/**
 * 字符串匹配RK算法,BF算法的升级版本

 */
public class RK {

    /**
     * 假设只匹配字母,所以d等于26
     * @param str 主串
     */
    public static int rabinKarp(String str, String pattern){
        int size1 = str.length();
        int size2 = pattern.length();

        //哈希时需要用到进制计算,这里只涉及26个字母所以使用26进制
        int d = 26;
        //防止hash之后的值超出int范围,对最后的hash值取模
        //q取随机素数,满足q*d < INT_MAX即可
        int q = 144451;

        //str子串的hash值
        int strCode = str.charAt(0) - 'a';
        //pattern的hash值
        int patternCode = pattern.charAt(0) - 'a';
        //d的size2-1次幂,hash计算时,公式中会用到
        int h = 1;

        //计算sCode、pCode、h
        for (int i = 1; i < size2; i++) {
            patternCode = (d*patternCode + pattern.charAt(i)-'a') % q;
            //计算str第一个子串的hash
            strCode = (d*strCode + str.charAt(i)-'a') % q;
            h = (h*d) % q;
        }

        //最大需要匹配的次数
        int frequency = size1 - size2 + 1;
        //字符串开始匹配,对patternCode和strCode开始比较,并更新strCode的值
        for (int i = 0; i < frequency; i++) {
            if(strCode == patternCode && ensureMatching(i, str, pattern)){
                return i;
            }
            //更新strCode的值,即计算str[i+1,i+m-1]子串的hashCode
            strCode = ((strCode - h*(str.charAt(i)-'a'))*d + str.charAt(i+size2) - 'a');
        }
        return -1;
    }

    /**
     * hash值一样并不能完全确保字符串一致,所以还需要进一步确认
     * @param i hash值相同时字符串比对的位置
     */
    private static boolean ensureMatching(int i, String str, String pattern) {
        String strSub = str.substring(i, i+pattern.length());
        return strSub.equals(pattern);
    }

    public static void main(String[] args) {
        String str = "abcabcabc";
        String pattern = "cabc";
        System.out.println("第一次出现的位置:" + rabinKarp(str, pattern));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值