算法#15--子字符串查找算法汇总和代码详解

本文汇总了五种子字符串查找算法:暴力算法、KMP算法、BoyerMoore算法和RabinKarp算法。详细介绍了每种算法的原理,并提供了对应的代码实现。KMP算法利用确定有限状态自动机(DFA)避免不必要的回退,BoyerMoore算法采用跳跃式匹配,RabinKarp算法通过散列函数快速比较。
摘要由CSDN通过智能技术生成

1.算法汇总

首先,来看一张汇总表,本文会将表里的每种算法作详细介绍。代码和逻辑比较长,可以根据目录跳着看。

2.暴力算法

在文本中可能出现匹配的任何地方都检查是否存在。原理很简单,直接看代码就可以懂。

实现代码


//暴力子字符串查找
public class ViolenceSubStringSearch 
{
    @SuppressWarnings("unused")
    public static int search(String pat, String txt)
    {
        int M = pat.length();
        int N = txt.length();
        for(int i = 0; i <= N-M; i++)
        {
            int j;
            for(j = 0; j < M; j++)
            {
                if(txt.charAt(i + j) != pat.charAt(j));
                break;
            }
            if(j == M)
            {
                return i;   //找到匹配
            }
        }
        return N;           //未找到匹配
    }
}

运行轨迹:

3.KMP算法

KMP算法的基本思想是当出现不匹配是,就能知晓一部分文本的内容(因为在匹配失败之前它们已经和模式匹配)。我们可以利用这些信息避免将指针回退到所有这些已知的字符之前。

KMP的主要思想是提前判断如何重新开始查找,而这种判断只取决于模式本身

在KMP子字符串查找算法中,不会回退文本指针i,而是使用一个数组dfa[][]来记录匹配失败时模式指针j应该回退多远。dfa[][]称为确定有限状态自动机(DFA)。

如何构造dfa,即DFA应该如何处理下一个字符?

和回退是的处理方式相同,除非在pat.charAt(j)处匹配成功,这时DFA应该前进到状态j+1.例如,对于ABABAC,要判断在j=5时匹配失败后DFA应该怎么做。通过DFA可以知道完全回退之后算法会扫描BABA并到达状态3,因此可以将dfa[][3]复制到dfa[][5]并将C所对饮的元素的值设为6.因为在计算DFA的地j个状态时只需要知道DFA是如何处理前j-1个字符的,所以总能从尚不完整的DFA中得到所需的信息。

最后一个关键的细节,如何维护重启位置X,因为X< j,所以可以由已经构造的DFA部分来完成这个任务–X的下一个值是dfa[pat.charAt(j)][X].

总结下,对于每个j,DFA会:

  • 将dfa[][X]复制到dfa[][j](对于失败的情况)
  • 将dfa[pat.charAt(j)][j]设为j+1(对于匹配成功的情况)
  • 更新X。

如下图:

实现代码


//KMP子字符串查找
public class KMP 
{
   
    private final int R;       // the radix
    private int[][] dfa;       // the KMP automoton

    private char[] pattern;    // either the character array for the pattern
    private String pat;        // or the pattern string

    /**
     * Preprocesses the pattern string.
     *
     * @param pat the pattern string
     */
    public KMP(String pat) 
    {
        this.R = 256;
        this.pat = pat;

        // build DFA from pattern
        int m = pat.length();
        dfa = new int[R][m]; 
        dfa[pat.charAt(0)][0] = 1; 
        for (int x = 0, j = 1; j < m; j++) 
        {
            for (int c = 0; c < R; c++) 
            {
                dfa[c][j] = dfa[c][x];     // Copy mismatch cases. 
            }
            dfa[pat.charAt(j)][j] = j+1;   // Set match case. 
            x = dfa[pat.charAt(j)][x];     // Update restart state. 
        } 
    } 

    /**
     * Preprocesses the pattern string.
     *
     * @param pattern the pattern string
     * @param R the alphabet size
     */
    public KMP(char[] pattern, int R) 
    {
        this.R = R;
        this.pattern = new char[pattern.length];
        for (int j = 0; j < pattern.length; j+
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值