【数据结构】串的模式匹配(KMP+朴素模式匹配)

news2024/11/15 8:45:30

2.串的模式匹配

  • 什么是字符串的模式匹配?

    在主串中找到与模式串相同的子串,并返回其所在位置。

    • 模式串:要匹配的一串。注:子串是主串的一部分,一定在主串中存在,但模式串不一定在主串中找得到。

2.1 朴素模式匹配算法

  • 思路

    暴力求解,一个字符一个字符对比下去。

  • 代码思路

    1.给主串一个指针 i,模式串指针 j,两个指针都指向第一个字符;

    2.若 i 和 j 所指字符相等,i+1,j+1;

    3.若 i 和 j 所指字符不相同,j 回到模式串第一个字符,i 指向下一个子串起始位置;

    4.若 j 超过模式串的长度,则匹配成功。

int Index(SString S,SString T){
    int i=1,j=1; //分别扫描主串和模式串
    while(i<S.length && j<=T.length){
        if(S.ch[i]==T.ch[j]){
            i++;j++; //继续比较后继字符
        }
        else{
            i=i-j+2; //到下一个子串的起始位置
            j=1;
        }
    }
    if(j>T.length)
        return i-T.length;
    else
        return 0;
}
  • 时间复杂度

    最坏情况:每个子串都要对比m个字符,共n-m+1个子串,复杂度= O ( ( n − m + 1 ) m ) = O ( n m ) O((n-m+1)m)=O(nm) O((nm+1)m)=O(nm)

2.2 KMP算法

  • 核心思想

    从模式串本身的结构着手,若已匹配相等的前缀序列中有某个后缀正好是模式串的前缀,则可将模式串向后滑动到与这些相等字符对齐的位置。

    • 设置next数组,next[a]=b意思为:

      ​ 当模式串中第a个元素匹配失败时,令主串指针i不变,模式串指针j=b。

      ​ 即当第a个元素匹配失败时,模式串回溯到第b个元素继续与主串匹配。

    • KMP算法=模式匹配过程+next数组求解

  • 时间复杂度

    O ( m + n ) O(m+n) O(m+n)

    其中,求next数组时间复杂度 O ( m ) O(m) O(m)

    模式匹配过程最坏时间复杂度 O ( n ) O(n) O(n)

2.2.1 模式匹配
  • 模式匹配过程(还未求next数组)

    1.分别设置i和j指针,指向主串和模式串;

    2.如果i和j指针指向的字符相同,i和j都加1;

    3.如果不相同,j回溯到模式串的上一个字符,即j=next[j]

    4.如果j等于0(模式串第一个元素下标为1),则i和j都加1。

    int Index_KMP(SString S,SString T,int next[]){
        int i=1,j=1;
        while(i<=S.length&&j<=T.length){
            if(j==0||S.ch[i]==T.ch[j]){
                i++;
                j++;
            }
            else{
                j=next[j];
            } 
        }
        if(j>T.length)
            return i-T.length;
        else
            return 0;
    }
    
2.2.2 求next数组
  • next数组作用

    当模式串的第j个字符失配时,从模式串的第next[j]个继续往后匹配。

  • next数组手算方法

    1.对于任何模式串:next[1]=0,next[2]=1

    2.对其他的next:在不匹配的位置前,划一条分界线,模式串一步步往后退,直到分界线前能对上,或模式串完全跨过分界线为止。此时j指哪,next数组值就是多少。

    • next[i] 存储的是 T[1:i] 这个子串的最长公共前后缀的长度。
  • next数组的优化

    next数组优化为nextval

    在原next数组基础上,若j对应的模式串元素和next[j]对应的模式串元素相等,则令nextval[j]=nextval[next[j]]

    nextval[1]=0;
    for(int j=2;j<=T.length;j++){
        if(T.ch[next[j]]==T.ch[j])
            nextval[j]=nextval[next[j]];
        else
            nextval[j]=next[j];
    }
    
*完整代码 KMP
#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>

#define MaxSize 99

typedef struct {
	char ch[MaxSize];
	int length;
}SString;

void StrAssign(SString& T, char chars[]) {
	for (int i = 0; i <= strlen(chars); i++)
		T.ch[i+1] = chars[i];
	T.length = strlen(chars);
}

void PrintS(SString S) {
	printf("Str:");
	for (int i = 1; i <= S.length; i++)
		printf("%c", S.ch[i]);
	printf("\n");
}

//KMP模式匹配算法
//S:主串
//T:模式串
int Index_KMP(SString S, SString T, int next[]) {
	int i = 1; //主串S的指针
	int j = 1; //模式串T的指针,数组下标都从1开始
	while (i <= S.length && j <= T.length) {
		if (j == 0 || S.ch[i] == T.ch[j]) { //模式串已到头或当前字符相同
			i++; j++; //继续比较后继字符
		}
		else {
			j = next[j]; //模式串向右移动
		}
	}
	if (j > T.length)
		return i - T.length; //匹配成功
	else
		return 0;
}

//求next数组
void get_next(SString T, int next[]) {
	int i = 1, j = 0;
	next[1] = 0;
	while (i < T.length) {
		if (j == 0 || T.ch[i] == T.ch[j]) { //当前字符与前缀字符相同
			i++; j++;
			next[i] = j; //当前位置的next值为前缀字符个数
		}
		else {
			j = next[j]; //不相同则回溯
		}
	}
}

//next数组优化
void get_nextval(SString T, int nextval[]) {
	int i = 1, j = 0;
	nextval[1] = 0;
	while (i < T.length) {
		if (j == 0 || T.ch[i] == T.ch[j]) { //当前字符与前缀字符相同
			i++; j++;
			if (T.ch[i] != T.ch[j])
				nextval[i] = j; //当前位置的nextval值为前缀字符个数
			else
				nextval[i] = nextval[j]; //如果当前字符与前缀字符相同,则继续向前递归
		}
		else {
			j = nextval[j]; //不相同则回溯
		}
	}
}

int main() {
	SString S, T;
	char s[] = "abcabcde";
	char t[] = "abcd";

	StrAssign(S, s);
	StrAssign(T, t);
	PrintS(S);
	PrintS(T);

	int next[MaxSize];
	get_next(T, next);
	int nextval[MaxSize];
	get_nextval(T, nextval);

	int pos = Index_KMP(S, T, next);
	if (pos != 0) {
		printf("Pattern found at position: %d\n", pos);
	}
	else {
		printf("Pattern not found.\n");
	}

	pos = Index_KMP(S, T, nextval);
	if (pos != 0) {
		printf("Pattern found at position: %d\n", pos);
	}
	else {
		printf("Pattern not found.\n");
	}

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1518360.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

upload文件上传漏洞复现

什么是文件上传漏洞&#xff1a; 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚本或者WebShell等。“…

uniapp-vue3 项目初始化集成配置【开箱即用】

地址 https://gitee.com/charrie/vue3-uniapp-init 部分截图展示 技术说明 采用vue3viteuniapp技术栈&#xff0c;setup语法糖编码方式使用完全免费的sard-uniapp组件库引入unocss量子化样式引擎&#xff0c;动态css不用自己写样式&#xff0c;引用class即可&#xff0c;降低…

计算机网络(6)-----传输层

目录 一.传输层 二.UDP协议 1.UDP的特点&#xff1a; 2.UDP的首部格式&#xff1a; 3.UDP校验的过程&#xff1a; 三.TCP协议 1.TCP协议的特点 2.TCP报文段首部格式 3.TCP的连接管理 &#xff08;1&#xff09;连接建立&#xff08;三次握手&#xff09; &#xff0…

Spring Web MVC入门(1)

什么是Spring Web MVC? 定义:Spring Web MVC是基于Servlet构建的原始Web框架,从一开始就包含在Spring框架中.它的正式名称"Spring Web MVC"来自其源模块的名称(Spring-webmvc),但是它通常被称为"Spring MVC". 什么是Servlet? Servlet是一种实现动态页面…

【C++】排序算法

目录 一、排序算法概述 二、初级排序算法 三、进阶排序算法 四、分治思想排序 五、哈希思想排序 六、分割思想排序 一、排序算法概述 在C语言中&#xff0c;通常需要手写排序算法实现对数组或链表的排序&#xff0c;但是在C中&#xff0c;标准库中的<algorithm>头…

【兔子机器人】实现从初始状态到站立

一、遥想星空up主的方法 由于我有卡位结构&#xff0c;无法做到劈腿&#xff0c;而且底盘也不一样&#xff0c;无法使用此方法 但是其代码思想是可以借鉴的。 参考视频&#xff1a; 【【开源啦&#xff01;】无刷轮腿平衡机器人】 【精准空降到 01:16】 https://www.bilibili…

C++类和对象一

#include <iostream> using namespace std;//设计一个学生类 class CStudent {public: //公有成员void InputData(){cout << "请输入学号";cin >> sno;cout << "请输入姓名";cin >> sname;cout << "请输入分…

RabbitMq踩坑记录

1、连接报错&#xff1a;Broker not available; cannot force queue declarations during start: java.io.IOException 2.1、原因&#xff1a;端口不对 2.2、解决方案&#xff1a; 检查你的连接配置&#xff0c;很可能是你的yml里面的端口配置的是15672&#xff0c;更改为5672即…

第110讲:Mycat实践指南:指定Hash算法分片下的水平分表详解

文章目录 1.应用指定Hash算法分片的概念2.使用应用指定Hash算法分片对某张表进行水平拆分2.1.在所有的分片节点中创建表结构2.2.配置Mycat实现应用指定Hash算法分片的水平分表2.2.1.配置Schema配置文件2.2.2.配置Rule分片规则配置文件2.2.3.配置Server配置文件2.2.4.重启Mycat …

交换机/路由器的存储介质-思科

交换机/路由器的存储介质-思科 本文主要介绍网络设备的存储介质组成。 RAM(random-accessmemory&#xff0c;随机访问存储器) RAM中内容断电丢失&#xff0c;主要用于运行操作系统、运行配置文件、IP 路由表:、ARP 缓存、数据包缓存区。 ROM(read-only memory&#xff0c;只…

多做【二叉搜索树】【数组转化为树】Leetcode 108. 将有序数组转换为二叉搜索树

【二叉搜索树】【数组转化为树】Leetcode 108. 将有序数组转换为二叉搜索树 解法1 递归 ---------------&#x1f388;&#x1f388; 108. 将有序数组转换为二叉搜索树 题目链接&#x1f388;&#x1f388;------------------- 解法1 递归 给你一个整数数组 nums &#xff0…

【Vue2】组件通信

父子通信 父 -> 子 子 -> 父 props 校验 props: {校验的属性名: {type: 类型, // Number String Boolean ...required: true, // 是否必填default: 默认值, // 默认值validator (value) {// 自定义校验逻辑return 是否通过校验}} },data 的数据是自己的 → 随便改pr…

【leetcode+深度/广度优先搜索】841. 钥匙和房间 (DFS,BFS)

leetcode-cn&#xff1a;leetcode面试75道精华&#xff1a;https://leetcode.cn/studyplan/leetcode-75/ 841.钥匙和房间&#xff1a;https://leetcode.cn/problems/keys-and-rooms/description/ 一、题目&#xff1a;841. 钥匙和房间 有 n 个房间&#xff0c;房间按从 0 到 n…

面试经典-16- 环形链表

题目 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#…

【数学建模】熵权法

之前我们学了层次分析法和topsis法&#xff0c;但是主观性十分强&#xff0c;有没有科学的方法得出权重呢&#xff1f;今天&#xff0c;我们来学习熵权法&#xff01; 基本概念&#xff1a; 熵权法&#xff0c;物理学名词&#xff0c;按照信息论基本原理的解释&#xff0c;信息…

尼伽OLED透明屏闪耀第24届中国零售业博览会,引领零售行业革新

2024 CHINA SHOP 第二十四届中国零售业博览会 3.13-15 上海 3.13-15日&#xff0c;第24届中国零售业博览会盛大开幕&#xff0c;起立科技&#xff08;旗下品牌&#xff1a;起鸿、尼伽&#xff09;携其自主研发的30寸OLED透明屏和移动AI透明屏机器人惊艳亮相&#xff0c;成为展…

租房网站|基于springboot框架+ Mysql+Java+B/S架构的租房网站设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 用户功能模块 管理员功能登录前台功能效果图 系统功能设计 数据库E-R图设计 lunwen参…

Redis-复制功能

0 序言 复制功能是Redis提供的多机功能中最基础的一个&#xff0c;这个功能是通过主从复制&#xff08;master-slave replication&#xff09;模式实现的&#xff0c;它允许用户为存储着目标数据库的服务器创建出多个拥有相同数据库副本的服务器&#xff0c;其中存储目标数据库…

【C++】stack、queue模拟实现+仿函数

stack、queue模拟实现仿函数 stack定义stack模拟实现 queue定义queue模拟实现 priority_queue定义priority_queue模拟实现 deque定义底层分析 容器适配器定义种类 仿函数控制类里面数据的比较逻辑回调函数仿函数两者区别 铁汁们&#xff0c;今天给大家分享一篇stack、queue模拟…

Kubernetes operator系列:webhook 知识学习【更新中】

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列文章&#xff0c;本节会对 kubernetes webhook 知识进行学习 本文的所有代码&#xff0c;都存储于github代码库&#xff1a;https://github.com/graham924/share-code-operator-st…