字符串匹配算法

BF(Brute Force)算法:暴力匹配

字符串A为主串,字符串B为模式串
A串从第0位开始,截取B长度的字符串,然后跟B串比较,不匹配的话+1从第1位截取B长度的字符串再比较。。。一直到超过长度

A=HelloWorld
B=Workd
第一次截取到Hello和World比较,不匹配
第二次截取到elloW和world比较,不匹配
第三次截取到lloWo。。。。
。。。

代码实现

public class Bfalth {
    public static boolean isMatch(String main, String sub) {
        for (int i = 0; i <= (main.length() - sub.length()); i++) {
            // 循环截取比较
            if (main.substring(i, i + sub.length()).equals(sub)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        System.out.println(isMatch("HelloWorld", "World"));
    }
}
Rk(Rabin-Karp)算法

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

设计一个hash算法: 将字符串转化成整数,利用K进制的方式
数字1-0 : 10进制(K=10)
123=10101+10*2+3
小写字母a-z:26进制
大小写字母a-Z:52进制
大小写字母+1-0:62进制

字符串“abc”转化成hash值的算法是: a的ASCII码是97
b的ASCII码是98 c的ASCII码是99
972626+98*26+99=68219
偏移97
(97-97)2626+(98-97)*26+(99-97)=68219
代码实现

public class RKalth {
    public static boolean isMatch(String main, String sub) {
        //算出子串的hash值
        int hash_sub = strToHash(sub);
        for (int i = 0; i <= (main.length() - sub.length()); i++) {
        // 主串截串后与子串的hash值比较
            if (hash_sub == strToHash(main.substring(i, i + sub.length()))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 支持 a-z 二十六进制 * 获得字符串的hash值
     * @param src
     *
     * @return
     */
    public static int strToHash(String src) {
        int hash = 0;
        for (int i = 0; i < src.length(); i++) {
            hash *= 26;
            hash += src.charAt(i) - 97;
        }
        return hash;
    }

    public static void main(String[] args) {
        System.out.println(isMatch("HelloWorld", "World"));
    }
}
BM(Boyer-Moore)算法:滑动算法

坏字符规则:
它是按照模式串下标从大到小的顺序,倒着匹配的
在这里插入图片描述

我们从模式串的末尾往前倒着匹配,当我们发现某个字符没法匹配的时候。我们把这个没有匹配的字符叫作坏字符(主串中的字符)。

在这里插入图片描述

字符 c 与模式串中的任何字符都不可能匹配。这个时候,我们可以将模式串直接往后滑动三位,将模式 串滑动到 c 后面的位置,再从模式串的末尾字符开始比较。

在这里插入图片描述

滑动到新位置后,a成了新的坏字符,坏字符 a 在模式串中是存在的,模式串中下标是 0 的位置也是字符 a。这种情况下,我们可以将模式串 往后滑动两位,让两个 a 上下对齐,然后再从模式串的末尾字符开始,重新匹配。
在这里插入图片描述

当发生不匹配的时候,我们把坏字符对应的模式串中的字符下标记作 si。如果坏字符在模式串中存在, 我们把这个坏字符在模式串中的下标记作 xi。如果不存在,我们把 xi 记作 -1。那模式串往后移动的位 数就等于 。(下标,都是字符在模式串的下标)

第一次移动3位
c在模式串中不存在,所以 xi=-1 ,移动位数n=2-(-1)=3
第二次移动2位
a在模式串中存在,xi=0 ,移动位数n=2-0=2

代码实现

public class BMalth {

    private static final int SIZE = 256; // 全局变量或成员变量

    /**
     * @param b
     * @param m
     * @param dc
     */
    private static void generateBC(char[] b, int m, int[] dc) {
        for (int i = 0; i < SIZE; ++i) {
            dc[i] = -1; // 初始化 bc 模式串中没有的字符值都是-1
        }
        //将模式串中的字符希写入到字典中
        for (int i = 0; i < m; ++i) {
            int ascii = (int) b[i]; // 计算 b[i] 的 ASCII 值
            dc[ascii] = i;
        }
    }

    /**
     * 坏字符
     *
     * @param a 主串
     * @param b 模式串
     * @return
     */
    public static int bad(char[] a, char[] b) {
        //主串长度
        int n = a.length;
        //模式串长度
        int m = b.length;
        //创建字典
        int[] bc = new int[SIZE];
        // 构建坏字符哈希表,记录模式串中每个字符最后出现的位置
        generateBC(b, m, bc);
        // i表示主串与模式串对齐的第一个字符
        int i = 0;
        while (i <= n - m) {
            int j;
            for (j = m - 1; j >= 0; --j) {// 模式串从后往前匹配
                //i+j : 不匹配的位置
                if (a[i + j] != b[j]) {
                    break;
                }
                // 坏字符对应模式串中的下标是j
            }
            if (j < 0) {
                return i; // 匹配成功,返回主串与模式串第一个匹配的字符的位置
            }
            // 这里等同于将模式串往后滑动j-bc[(int)a[i+j]]位
            // j:si  bc[(int)a[i+j]]:xi
            i = i + (j - bc[(int) a[i + j]]);
        }
        return -1;
    }

    public static void main(String[] args) {
        String s1 = "abcabcabc";
        String s2 = "bca";
        System.out.println(bad(s1.toCharArray(), s2.toCharArray()));

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值