数据结构与算法之字符串匹配算法

字符串匹配算法是在一个文本串中寻找一个模式串出现的算法。其基本原理是在文本串中逐个比较模式串的字符,如果匹配则继续比较下一个字符,如果不匹配则将模式串向右移动一位,继续比较。

以下是一些常用的字符串匹配算法:

  1. 暴力匹配法(Brute Force):从文本串的第一个字符开始,逐个比较模式串和文本串中的字符,如果不匹配则将模式串向右移动一位,继续比较。

  2. KMP算法(Knuth-Morris-Pratt):利用模式串本身的特点,在匹配失败时不回溯文本串,而是回溯模式串,让其尽量多地向右移动一位,以提高匹配效率。

  3. BM算法(Boyer-Moore):从文本串的末尾开始,逐个比较模式串和文本串中的字符,如果不匹配则根据字符出现的位置和匹配的历史记录,确定模式串向右移动的距离,以减少比较次数。

  4. Sunday算法:在字符串匹配过程中,每次比较文本串和模式串中的字符时,都将模式串向右移动一位,直到模式串中的某个字符在文本串中第一次出现的位置不为-1为止,此时将模式串向右移动相应的距离,以减少比较次数。

这些字符串匹配算法各有其优缺点,根据不同的应用场景可以选择不同的算法。

在这里插入图片描述

一、C 实现 字符串匹配算法 及代码详解

字符串匹配算法是在一个字符串中查找子串的过程。在计算机领域中,字符串匹配问题是一类经典问题,有很多有效的算法可供选择,其中最常用的算法是暴力匹配算法和KMP算法。

下面是一个简单的C语言实现字符串匹配的暴力算法,即朴素算法:

#include <stdio.h>
#include <string.h>

int naive_search(char* str, char* pattern) {
    int n = strlen(str);
    int m = strlen(pattern);
    int i, j;
    for (i = 0; i < n - m + 1; i++) {
        for (j = 0; j < m; j++) {
            if (str[i + j] != pattern[j]) {
                break;
            }
        }
        if (j == m) {
            return i;
        }
    }
    return -1;
}

int main() {
    char str[] = "hello world";
    char pattern[] = "world";
    int pos = naive_search(str, pattern);
    if (pos == -1) {
        printf("Pattern not found\n");
    } else {
        printf("Pattern found at position %d\n", pos);
    }
    return 0;
}

该算法的基本思想是:从第一个字符开始,依次比较子串与字符串的字符,直到找到第一个匹配的字符,然后再比较后续的字符是否匹配,如果不匹配,则回到第一个匹配的字符的下一个字符开始比较。

时间复杂度为O(mn),其中m和n分别为模式串和文本串的长度。在实际应用中,暴力算法很少被使用,因为其效率比较低,但是该算法实现简单,易于理解,是理解其他更复杂的字符串匹配算法的基础。

在这里插入图片描述

二、C++ 实现 字符串匹配算法 及代码详解

字符串匹配算法是指在一个文本串(比如一个长文章)中查找一个模式串(比如一个单词)的过程。常见的字符串匹配算法有暴力匹配算法、KMP算法、Boyer-Moore算法等。

这里我们介绍一下C++实现KMP算法的方法,代码如下:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

vector<int> getNext(string &p) {
    int m = p.size();
    vector<int> next(m, 0);
    int k = 0;
    for (int i = 1; i < m; i++) {
        while (k > 0 && p[i] != p[k]) {
            k = next[k - 1];
        }
        if (p[i] == p[k]) {
            k++;
        }
        next[i] = k;
    }
    return next;
}

int KMP(string &s, string &p) {
    int n = s.size();
    int m = p.size();
    if (n < m) {
        return -1;
    }
    auto next = getNext(p);
    int k = 0;
    for (int i = 0; i < n; i++) {
        while (k > 0 && s[i] != p[k]) {
            k = next[k - 1];
        }
        if (s[i] == p[k]) {
            k++;
        }
        if (k == m) {
            return i - m + 1;
        }
    }
    return -1; 
}

int main() {
    string s = "ababcabcacbab";
    string p = "abcac";
    cout << KMP(s, p) << endl;  // output: 5
    return 0;
}

代码详解:

  1. 首先我们定义了一个函数 getNext(),用来计算模式串的 next 数组, next 数组定义如下:

    next[i] 表示当模式串中第i个字符与文本串不匹配时,模式串要跳过的字符数。也就是在模式串中,0~next[i-1] 与第 i-next[i] ~i-1 个字符相同。

    这个数组将在 KMP 算法中被用到,用于加速匹配的过程。

  2. 定义了主函数 KMP,我们先计算出模式串的 next 数组。

  3. 然后我们在文本串中逐个字符匹配模式串,如果当前字符匹配,则继续匹配下一个字符。如果不匹配,我们利用 next 数组,跳过一些字符再匹配。当匹配到最后一个字符时,如果匹配成果,返回模式串在文本串中的起始位置。

  4. 如果匹配失败,则返回 -1。

总结:

KMP 算法通过计算模式串的 next 数组,在匹配过程中跳过一些不必要的字符,从而提高了匹配的效率。虽然 KMP 算法的时间复杂度与暴力匹配算法相同,但是其常数因子较小,实际运行中比暴力算法快得多。

在这里插入图片描述

三、Java 实现 字符串匹配算法 及代码详解

字符串匹配算法是计算机科学中经典的问题之一,它的目的是在文本字符串中查找一个模式字符串的出现。

在 Java 中,有以下几种常见的字符串匹配算法:

  1. Brute-Force 算法(暴力匹配算法)

Brute-Force 算法是一种朴素的字符串匹配算法,它的思路是将模式串从文本串的第一个字符开始,逐一比较字符是否相同,如果不同,就移动模式串到文本串的下一个字符位置。这个过程一直重复,直到找到一个匹配或者到文本串的末尾为止。

代码实现:

public static int search(String text, String pattern) {
    int n = text.length();
    int m = pattern.length();
    for (int i = 0; i <= n - m; i++) {
        int j;
        for (j = 0; j < m; j++) {
            if (text.charAt(i + j) != pattern.charAt(j)) {
                break;
            }
        }
        if (j == m) {
            return i;
        }
    }
    return -1;
}
  1. KMP 算法(Knuth-Morris-Pratt 算法)

KMP 算法是一种高效的字符串匹配算法,它的核心思想是利用模式串本身的信息,避免重复比较已经匹配过的字符。

具体来说,KMP 算法不是从文本串的第一个字符开始匹配,而是从模式串的第一个字符开始匹配,如果当前字符匹配成功,就继续比较下一个字符,否则根据模式串的信息,移动模式串到某个位置继续匹配。

代码实现:

public static int search(String text, String pattern) {
    int n = text.length();
    int m = pattern.length();
    int[] next = getNext(pattern);
    int i = 0;
    int j = 0;
    while (i < n && j < m) {
        if (j == -1 || text.charAt(i) == pattern.charAt(j)) {
            i++;
            j++;
        } else {
            j = next[j];
        }
    }
    if (j == m) {
        return i - j;
    } else {
        return -1;
    }
}

private static int[] getNext(String pattern) {
    int m = pattern.length();
    int[] next = new int[m];
    next[0] = -1;
    int i = 0;
    int j = -1;
    while (i < m - 1) {
        if (j == -1 || pattern.charAt(i) == pattern.charAt(j)) {
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
    return next;
}
  1. BM 算法(Boyer-Moore 算法)

BM 算法是一种快速的字符串匹配算法,它的核心思想是利用模式串中的字符出现位置和文本串的匹配过程,尽量减小不匹配字符的比较次数。

具体来说,BM 算法分别将模式串和文本串从后往前匹配,如果当前字符不匹配,则根据模式串中该字符出现的位置和文本串中对应字符的位置,选择将模式串往右移动几个位置,或者将文本串往右移动几个位置。

代码实现:

public static int search(String text, String pattern) {
    int n = text.length();
    int m = pattern.length();
    int[] last = buildLast(pattern);
    int i = m - 1;
    int j = m - 1;
    while (i < n && j >= 0) {
        if (text.charAt(i) == pattern.charAt(j)) {
            i--;
            j--;
        } else {
            int x = last[text.charAt(i)];
            i += m - Math.min(j, 1 + x);
            j = m - 1;
        }
    }
    if (j == -1) {
        return i + 1;
    } else {
        return -1;
    }
}

private static int[] buildLast(String pattern) {
    int m = pattern.length();
    int[] last = new int[256];
    Arrays.fill(last, -1);
    for (int i = 0; i < m; i++) {
        last[pattern.charAt(i)] = i;
    }
    return last;
}

这三种字符串匹配算法各有优缺点,在实际应用中需要根据具体情况选择合适的算法。

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值