当前位置: 首页 > article >正文

字符串算法之Rabin-Karp 算法(字符串匹配)详细解读

Rabin-Karp算法是一种高效的字符串匹配算法,特别适用于在文本中查找多个模式串或在大文本中查找子串。它的主要思想是使用哈希函数将模式串和文本串的子串映射到一个数字,然后比较这些哈希值,以此来判断是否存在匹配。Rabin-Karp算法的平均时间复杂度为 O(n+m),但在最坏情况下,时间复杂度为 O(n⋅m)。

Rabin-Karp算法的基本原理

  1. 哈希函数:通过哈希函数将模式串和文本串的子串转换为哈希值。常用的哈希函数是多项式哈希(polynomial hashing),可以使用以下公式:

                    h(s)=(s[0]×dm−1+s[1]×dm−2+…+s[m−1]×d0)modq        ​​​​​​​

    其中:

    • s 是字符串
    • d 是字符集的大小(例如,ASCII字符集为256)
    • m 是模式串的长度
    • q 是一个大的素数,用于减少哈希冲突
  2. 滑动窗口:在文本串中使用一个长度为 m 的滑动窗口来提取子串,并计算其哈希值。然后将这个哈希值与模式串的哈希值进行比较。

  3. 哈希冲突处理:由于不同的字符串可能会产生相同的哈希值(哈希冲突),因此在哈希值匹配时,需要再次逐字符比较,以确认匹配。

Rabin-Karp算法的步骤

  1. 计算模式串的哈希值:计算模式串的哈希值。
  2. 计算文本串的初始哈希值:计算文本的前 m 个字符的哈希值。
  3. 比较哈希值
    • 如果哈希值匹配,则逐字符比较以确认匹配。
    • 如果不匹配,则通过滑动窗口向右移动一个字符,并更新哈希值。
  4. 重复步骤3,直到文本串的末尾。

Rabin-Karp算法的Java实现

以下是 Rabin-Karp算法的 Java 实现示例:

import java.util.ArrayList;
import java.util.List;

public class RabinKarpAlgorithm {
    private static final int d = 256; // 字符集大小
    private static final int q = 101; // 质数

    // Rabin-Karp字符串匹配算法
    public void rabinKarp(String text, String pattern) {
        int m = pattern.length();
        int n = text.length();
        int p = 0; // 模式串的哈希值
        int t = 0; // 文本串的哈希值
        int h = 1; // h 是 d^(m-1) % q

        // 计算 d^(m-1) % q
        for (int i = 0; i < m - 1; i++) {
            h = (h * d) % q;
        }

        // 计算模式串和文本串的初始哈希值
        for (int i = 0; i < m; i++) {
            p = (d * p + pattern.charAt(i)) % q;
            t = (d * t + text.charAt(i)) % q;
        }

        // 滑动窗口
        for (int i = 0; i <= n - m; i++) {
            // 如果哈希值相等,进一步比较字符
            if (p == t) {
                int j;
                for (j = 0; j < m; j++) {
                    if (text.charAt(i + j) != pattern.charAt(j)) {
                        break;
                    }
                }
                if (j == m) {
                    System.out.println("Pattern found at index: " + i);
                }
            }

            // 计算下一个窗口的哈希值
            if (i < n - m) {
                t = (d * (t - text.charAt(i) * h) + text.charAt(i + m)) % q;
                // 处理负值
                if (t < 0) {
                    t += q;
                }
            }
        }
    }

    public static void main(String[] args) {
        RabinKarpAlgorithm rabinKarp = new RabinKarpAlgorithm();
        String text = "GEEKS FOR GEEKS";
        String pattern = "GEEK";
        rabinKarp.rabinKarp(text, pattern); // 在文本中查找模式串
    }
}

代码解读

  1. 常量定义

    • d:字符集大小(在这里选择为256,即ASCII字符集)。
    • q:一个大的素数,用于减少哈希冲突。
  2. rabinKarp 方法

    • 计算模式串的哈希值和文本串的初始哈希值。
    • 使用滑动窗口遍历文本串,比较哈希值。如果哈希值相等,进一步逐字符比较以确认匹配。
    • 更新哈希值时,使用公式计算下一个窗口的哈希值。
  3. main 方法:创建 RabinKarpAlgorithm 实例,并在给定的文本串中查找指定的模式串。

Rabin-Karp算法的优缺点

优点
  • 适合多模式匹配:通过计算多个模式串的哈希值,可以在一次遍历中进行匹配。
  • 平均时间复杂度低:在大多数情况下,Rabin-Karp算法的时间复杂度为 O(n+m)。
缺点
  • 哈希冲突:需要处理哈希冲突,可能导致性能下降。
  • 最坏情况下的时间复杂度:在最坏情况下(所有字符都冲突),时间复杂度为 O(n⋅m)。
  • 额外的空间复杂度:需要存储哈希值,可能增加内存使用。

应用场景

  • Rabin-Karp算法在文本搜索、网络安全(如查找恶意代码片段)、DNA序列比对等领域具有广泛应用。其高效的匹配能力和适合多模式查找的特性使其在处理大量数据时非常有用。

http://www.kler.cn/a/349901.html

相关文章:

  • Arduino大师练成手册 -- 控制 MH-SD 卡模块
  • 【随手笔记】FFT资料整理
  • ui-automator定位官网文档下载及使用
  • unity学习20:time相关基础 Time.time 和 Time.deltaTime
  • Android - 通过Logcat Manager简单获取Android手机的Log
  • 华为数据之道-读书笔记
  • 打家劫舍系列 | Leetcode 198 | 213 | 337 | 动态规划 | 滚动数组
  • 51单片机红外通信——直流电机
  • leetcode桶排序
  • (10) GTest c++单元测试(mac版)
  • Python cachetools常用缓存算法汇总
  • Python的dataframe 排序
  • MySQL 【日期】函数大全(四)
  • ollama + fastgpt+m3e本地部署
  • AI视频监控卫士:免费开源,一键安装轻松实现智能监控
  • Unity客户端HR面面经
  • 人工智能学习框架
  • Springboot 接入 WebSocket 实战
  • AMBA:AHB的历史(从AHB2到AHB5)
  • 0基础能不能转行做网络安全?
  • linux信号 | 学习信号四步走 | 全解析信号的产生方式
  • Flume面试整理-常见的Sink类型
  • 中小型医院网站:Spring Boot开发策略
  • 安装TDengine数据库3.3版本和TDengine数据库可视化管理工具
  • 杂记9---C++工程目录一键生成脚本分享
  • 2015年-2016年 软件工程程序设计题(算法题)实战_c语言程序设计数据结构程序设计分析