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

字符串匹配:暴力法和KMP算法(C语言)

文章目录KMP算法1.串的定义1.1定长顺序存储和变长分配存储表示1.2 串的初始化2.串的匹配2.1 暴力查找2.2 KMP算法KMP算法的思想手动算next数组next数组值的规律代码全部代码KMP算法1.串的定义串字符串是一种特殊的线性表其数据元素是字符。它是计算机中处理文本信息的基本数据结构。char str[]“Hello world”数据结构的串没有“\0”,不同的编程语言是否用0°作为串的结束标志是没有定论的通过length来约束空间的长度也会更通用。1.1定长顺序存储和变长分配存储表示typedefstruct{charstr[maxSize1]//从0号索引l存储数据1是为了存储\0可选intlength;}typedefstruct{char*str;intlength;//动态分配空间}1.2 串的初始化与普通变量赋值操作不同串的赋值操作不能直接用来实现通过定义初始化函数来实现空间拷贝。//串头初始化字符串intstrAssign(StrType*str,constchar*ch);申请多两个0号不填KMP监视哨‘\0’还要填// tinaStr.h#pragmaoncetypedefstruct{char*str;intlength;}StrType;// 字符串赋值将ch指向的C字符串复制给strvoidstrAssign(StrType*str,constchar*ch);voidreleaseStr(StrType*str);intindex_simple(constStrType*str,constStrType*subStr);#includetinaStr.h#includestdlib.h// 为了 malloc 和 freevoidstrAssign(StrType*str,constchar*ch){// 如果str已经分配了内存先释放if(str-str){free(str-str);str-strNULL;}// 计算ch的长度intlen0;while(ch[len]){len;}// 如果长度为0则str为空串if(len0){str-strNULL;str-length0;return;}// 分配内存长度为len1包括结束符\0str-str(char*)malloc(sizeof(char)*(len2));if(!str-str){// 内存分配失败可以处理错误这里简单地将长度置0并返回str-length0;return;}// 复制字符包括结束符for(inti0;ilen;i){str-str[i1]ch[i];}str-lengthlen;}voidreleaseStr(StrType*str){ifstr{ifstr-str{free(str-str);}}2.串的匹配字符串匹配在主串中找到与模式串相同的子串并返回其所在位置。2.1 暴力查找假设法intindex_simple(constStrType*str,constStrType*subStr){inti1;intj1;intki;// 记录起始位置while(istr-lengthjsubStr-length){if(str-str[i]subStr-str[j]){i;j;}else{j1;k;ik;}}if(jsubStr-length){returnk;// 匹配成功返回起始位置}return0;// 匹配失败}// 测试函数voidtest01(constStrType*str,constStrType*pattern){intresindex_simple(str,pattern);printf(simple find index: %d\n,res);}intmain(){StrType str;StrType subStr;str.strNULL;subStr.strNULL;strAssign(str,ABCDABCABCABABCABCD);strAssign(subStr,ABCABCD);// 调用测试函数test01(str,subStr);releaseStr(str);releaseStr(subStr);return0;}2.2 KMP算法不匹配的字符之前一定是和模式串一致的是否可以从这个已知信息来确定模式失配时下次从模式串的第几个位置假设模式串为abcabd主串为“abcabxxxx“从主串s[1]开始匹配时在p[6]时失配既然在p[6]处失配那么说明s[1:5]的信息一定是模式串的p[1:5]所以按照朴素匹配算s[2]、s[3」… 开始匹配尝试是不是可以明确肯定不会成功。而从s[4]开始有可能成功P[1:5]“abcab”它的前缀不包括自身有“a”, “ab”, “abc”, “abca”P[1:5]“abcab后缀不包括自身有“b”, “ab”, “cab”, “bcab”。最长的公共前后缀是ab”长度为2第一次匹配从 s[1] 开始匹配成功前5个字符 主串 a b c a b x x x x ↑ ↑ ↑ ↑ ↑ × ← s[6] ≠ p[6] (x ≠ d) 模式 a b c a b d ↑ ↑ ↑ ↑ ↑ ↑ 1 2 3 4 5 6 已匹配部分s[1:5] abcab p[1:5]朴素算法的做法试每个位置❌从 s[2] 开始匹配text主串 a b c a b x x x x ↑ ← 从这里开始对齐p[1] 模式 a b c a b d ↑ 1 需要满足s[2] p[1] a 但已知s[2] b 所以❌ 必定失败 为什么已知s[2]b 因为s[2]在第一次匹配时已经看过❌从 s[3] 开始匹配主串 a b c a b x x x x ↑ ← 从这里开始对齐p[1] 模式 a b c a b d ↑ 1 需要满足s[3] p[1] a 但已知s[3] c 所以❌ 必定失败✅从 s[4] 开始可能成功主串 a b c a b x x x x ↑ ← 从这里开始对齐p[1] 模式 a b c a b d ↑ 1 需要满足s[4] p[1] a 已知s[4] a ✅ 满足 继续检查 主串 a b c a b x x x x ↑ ↑ ← 检查p[2] 模式 a b c a b d ↑ ↑ 1 2 需要满足s[5] p[2] b 已知s[5] b ✅ 满足 到这里已经匹配了前2个字符可能继续成功。KMP算法的思想当子串和模式串不匹配时主串指针i不回溯通过改变模式串指针j的值来确定子串从失配处和模式串的哪个位置进行比较因为模式串前面的信息在前面比较的时候已经知道信息了。如果能够存储子串失配后从模式串的哪个位置上进行比较就可以实现KMP算法故引入next数组专门存放这个值。显然next数组里的值只跟模式串有关因为模式串前面已经成功匹配的字符就表示子串中已经包含了这些字符。手动算next数组next数组Next数组记录的是模式串每个位置**“最长相同前后缀”的长度**。当匹配失败时模式串要往前退多少才能继续匹配而不是傻傻地只退1位。串的前缀包含第一个字符且不包含最后一个字符的子串串的后缀包含最后一个字符且不包含第一个字符的子串找前缀和后缀中相同的部分取最长的那个。 还是 abcab 前缀a, ab, abc, abca 后缀b, ab, cab, bcab 相同的只有 ab长度2 所以最长相同前后缀长度 2当第j个字符匹配失败由前[1j-1]个字符组成的串记为S手动计算就是根据这个S来决定的next[j的值S最长相等前后缀的长度1表示对于子串中前j-1个字符而言步骤规则1第一个字符的 Next 值 0因为前面没有字符了。规则2后面的字符按以下公式next[j] (前j-1个字符的串)的最长相同前后缀长度 1一句话解释已经匹配成功的部分如果有相同前后缀前缀部分肯定也能匹配所以跳过它们直接从相同部分的下一个开始比较。举例 模式串abcabd在p[6]失败时前5个字符abcab已匹配abcab有相同前后缀ab长度2前缀ab肯定能匹配因为后缀ab已匹配所以直接从p[3]开始比较21next[6] 2 1 3意思跳过前2个字符从第3个开始为什么 1长度2表示有2个字符肯定匹配但我们要比较的是下一个字符所以是已确定的匹配数 要检查的下一个位置next数组值的规律next[j]的值每次最多增加1模式串的最后一位字符不影响next数组的结果next数组的定义当主串与模式串的某一位字符不匹配时模式串要回退到的位置voidgetNext(StrType*subStr,intnext[]){inti1,j0;// 串从数组下标1位置开始存储//i 模式串短串的位置//j next数组值next[0]0;while(isubStr-length){if(j0||subStr-str[i]subStr-str[j]){i;j;next[i]j;}else{//不等往前看jnext[j];}}}代码voidgetNext(StrType*subStr,intnext[]){//next 填的为公共 前后缀长度加一inti1,j0;// 串从数组下标1位置开始存储//i 模式串短串的位置//j next数组值next[0]0;//i length 时不会进入循环 next索引最大为lengthwhile(isubStr-length){if(j0||subStr-str[i]subStr-str[j]){i;j;next[i]j;}else{//不等往前看jnext[j];}}}// KMP模式匹配算法intindexKMP(constStrType*str,constStrType*subStr,constintnext[]){inti1;// 主串当前位置intj1;// 子串当前位置while(istr-lengthjsubStr-length){//主串不动 子串动if(j0||str-str[i]subStr-str[j]){i;j;}else{jnext[j];}}if(jsubStr-length){returni-subStr-length;// 匹配成功返回起始位置}return0;// 匹配失败}全部代码stringKMP.h#includestdio.h#includestdlib.htypedefstruct{char*s;intlen;}strType;voidinitStr(strType*str);voidCopyStr(strType*str,constchar*s);intsimple_index(strType*str,strType*substr);intKMPIndex(strType*str,strType*substr);voidreleaseStr(strType*str);KMP和暴力#includestringKMP.hvoidinitStr(strType*str){str-len0;str-sNULL;}voidCopyStr(strType*str,constchar*s){if(str-s){free(str-s);str-sNULL;}intlen0;//分配多少空间while(s[len]){len;}//0位置不放字符以及\0str-smalloc(sizeof(strType)*(len2));if(str-sNULL)return;str-lenlen;//赋值for(inti0;ilen;i){//str-s[i 1] [1,len1]//s[i] [0,len]str-s[i1]s[i];}//检验copy成功printf(\n\n);for(inti0;ilen;i){printf(%c,str-s[i1]);}printf(\n\n);}intsimple_index(strType*str,strType*substr){inti1;//主串索引intj1;//模式串索引intki;//记录主串回溯位置 模式串回溯到开头while(istr-lenjsubstr-len){if(str-s[i]substr-s[j]){i;j;ki;}else{k;//主串移动一个位置匹配ik;j1;}}//循环结束模式串走到了末尾 证明是子串if(jsubstr-len){returni-substr-len;}return0;}//回溯数组next[i]//next[i][1,i-1]里面的公共前后缀个数1staticvoidgetnext(strType*substr,intnext[]){next[0]0;//不装东西next[1]0;intcur1;//当前模式串索引intk0;//next值while(cursubstr-len){//if (k 0) {//cur;//k;//索引2 只有一个//没有公共前后缀而且不是本身 next[2]01//next[cur] k;//continue;//}if(k0||substr-s[cur]substr-s[k]){cur;k;next[cur]k;}else{knext[k];}}/*for (int i 1; i cur; i) { printf(%d , next[i]); }*/}//主串不回溯 模式串回溯// 回溯数组next 模式串i位置不匹配时回溯的位置为next[i]intKMPIndex(strType*str,strType*substr){inti1;//主串索引intj1;//模式串索引而且和next数组值有关//空出第一位int*nextmalloc(sizeof(int)*(str-len1));if(nextNULL)return-1;getnext(substr,next);while(istr-lenjsubstr-len){if(j0||str-s[i]substr-s[j]){i;j;}else{jnext[j];}}if(jsubstr-len){returni-substr-len;}return0;}voidreleaseStr(strType*str){if(str-s){free(str-s);str-sNULL;}}voidtest01(){strType str;strType substr;initStr(str);initStr(substr);CopyStr(str,ABCDABCABCABABCABCD);CopyStr(substr,ABCABCD);//abaaabagabaaabaa/*int res simple_index(str, substr); printf(simple_index:%d\n, res);*/intresKMPIndex(str,substr);printf(KMPIndex:%d\n,res);}intmain(){test01();return0;}/*ABCDABCABCABABCABCD ABCABCD */

相关文章:

字符串匹配:暴力法和KMP算法(C语言)

文章目录KMP算法1.串的定义1.1定长顺序存储和变长分配存储表示1.2 串的初始化2.串的匹配2.1 暴力查找2.2 KMP算法KMP算法的思想手动算next数组next数组值的规律代码全部代码KMP算法 1.串的定义 串(字符串)是一种特殊的线性表,其数据元素是字…...

时间序列模型总体分类

目录 第一类:时间被“修理”的模型 (AR / MA / ARMA / ARIMA / SARIMA) 第二类:时间被“分解”为结构(Holt / Holt–Winters / BSTS) 第三类:时间 潜在状态的演化(Linear Gaussian SSM / Kalman Filter…...

jQuery vs Bootstrap:全面对比

jQuery vs Bootstrap:全面对比一、本质区别(核心定位)二、技术架构对比jQuery:JavaScript工具库Bootstrap:CSS框架 UI组件三、功能领域对比jQuery专注的领域Bootstrap专注的领域四、历史关系与演进依赖关系变化时代背…...

MathModelAgent:基于LLM智能体的数学建模自动化框架解析与实践

1. 项目概述:当数学建模遇上智能体如果你参与过数学建模竞赛,或者在工作中处理过需要将现实问题抽象为数学模型的任务,你大概率会记得那种感觉:面对一个全新的问题领域,你需要快速学习背景知识、定义变量、寻找合适的数…...

Milk-V Titan主板:RISC-V架构的迷你ITX高性能解决方案

1. Milk-V Titan主板概览:RISC-V架构的迷你ITX新选择Milk-V Titan是一款基于RISC-V架构的迷你ITX主板,搭载UltraRISC UR-DP1000八核处理器,主打高性能计算与扩展能力。作为市面上少有的支持PCIe Gen4 x16插槽的RISC-V主板,它填补了…...

多模态提示优化:释放大语言模型潜力的关键技术

1. 多模态提示优化的核心价值在2023年大语言模型爆发式发展的背景下,多模态大语言模型(MLLMs)正在重塑人机交互的范式。但许多开发者发现,同样的模型在不同团队手中表现差异巨大——这背后往往不是算力或数据的差距,而…...

基于LLaMA与LoRA的中文大模型低资源微调实战指南

1. 项目概述:中文低资源指令微调方案如果你关注过2023年初的AI社区,一定记得那场由Meta的LLaMA模型引发的“开源大模型狂欢”。一夜之间,仿佛人人都想拥有一个能理解指令、能对话、能写代码的“私人AI助手”。但现实很骨感:动辄数…...

PromptBridge技术:实现大模型提示词跨平台适配

1. 项目背景与核心价值在AI技术快速迭代的今天,大语言模型(LLM)已经成为各行业智能化转型的核心驱动力。但不同厂商的模型架构、训练数据和接口规范存在显著差异,这导致针对特定模型精心设计的提示词(prompt&#xff0…...

GPTyped:基于AI的TypeScript类型自动生成工具实战指南

1. 项目概述:当TypeScript遇见GPT,一种全新的代码生成范式如果你和我一样,长期在TypeScript生态里摸爬滚打,那你一定对类型安全又爱又恨。爱的是它能在编译期就揪出无数低级错误,恨的是为了写出完美的类型定义&#xf…...

LLM推理优化:Reinforce-Ada-Seq自适应采样技术解析

1. 项目背景与核心价值在大型语言模型(LLM)推理过程中,计算资源消耗一直是制约实际应用的关键瓶颈。传统固定采样策略往往导致大量无效计算,特别是在处理长文本或复杂推理任务时,这种低效问题尤为突出。Reinforce-Ada-…...

【读书笔记】《武则天》

《武则天》:中国历史上唯一女皇帝武则天一、读这本书的理由:打破文化遮蔽 我们对武则天的认知,大多来自电视剧——冯宝宝版、刘晓庆版、《大明宫词》……这些影视作品中蕴含着大量民间传说、文化偏见与戏剧冲突的需要,与历史事实相…...

安卓应用开发中 Android 11+ 软件包可见性问题详解

文章目录安卓应用开发中 Android 11 软件包可见性问题详解一、问题现象二、产生原因2.1 软件包可见性策略2.2 受影响的 API2.3 为什么引入此限制&#xff1f;三、解决方案3.1 使用 <queries> 声明需要访问的应用3.1.1 按包名声明3.1.2 按 Intent 过滤器声明3.1.3 混合使用…...

Remotion 用 React 写视频的设计原则与生产场景

教育培训内容创作者经常面临一个棘手的场景&#xff1a;把 PDF 课件转成带讲解音频和动画的完整教学视频时&#xff0c;传统剪辑软件总是在音频同步、批量个性化、以及后期迭代上卡住。手动对齐每一帧动画&#xff0c;调整几十个课件的变体&#xff0c;时间和精力消耗巨大。而 …...

AI自动化内容发布:基于MCP协议构建Substack智能助手

1. 项目概述&#xff1a;一个让AI帮你写Substack的“智能副驾”最近在折腾AI工作流的朋友&#xff0c;可能都听说过MCP&#xff08;Model Context Protocol&#xff09;这个概念。简单来说&#xff0c;它就像给AI大模型&#xff08;比如Claude、GPT&#xff09;装上了一套标准化…...

LabVIEW中NI-DAQmx触发技术及应用

NI-DAQmx触发技术是LabVIEW环境下数据采集&#xff08;DAQ&#xff09;的核心功能&#xff0c;用于实现采集过程与外部事件同步&#xff0c;仅捕获感兴趣信号区域&#xff0c;节省硬件带宽与内存。其支持模拟、数字两类触发及预触发、后触发两种采集模式&#xff0c;可通过LabV…...

数据采集系统隐性成本分析与NI-DAQmx技术优势

1. 数据采集系统的隐性成本解析在工业自动化和测试测量领域&#xff0c;数据采集&#xff08;DAQ&#xff09;系统是获取物理世界信息的关键通道。从业十余年&#xff0c;我见过太多项目在初期只关注硬件采购成本&#xff0c;却在后期被各种隐性时间成本拖垮预算。根据行业调查…...

css:什么是塌陷?

现象&#xff1a; 当父元素的所有子元素都设置了浮动&#xff08;float&#xff09;&#xff0c;而父元素没有设置固定高度时&#xff0c;父元素的高度会变为 0&#xff0c;就像“塌陷”了一样。html //效果&#xff1a;父元素背景看不见&#xff0c;边框缩成一条线&#xff0c…...

RAPTOR框架:四旋翼无人机零样本智能控制技术解析

1. RAPTOR框架概述&#xff1a;重新定义四旋翼智能控制边界在无人机控制领域&#xff0c;传统方法往往需要针对每个新任务进行繁琐的参数调整和模型训练。RAPTOR&#xff08;Reinforced Adaptive Pre-trained Transformer for Robotic Operations&#xff09;框架的提出&#x…...

基于MCP协议与微服务架构的AI原生任务管理系统部署与实战

1. 项目概述&#xff1a;为AI而生的任务管理革命 如果你和我一样&#xff0c;每天都在和各种AI助手打交道——Claude、GPT、Cursor、Windsurf&#xff0c;那你肯定遇到过这个痛点&#xff1a;想法和指令在对话里转瞬即逝&#xff0c;没有一个地方能系统地让AI帮你把任务管起来。…...

5个步骤让电脑风扇彻底静音:FanControl深度解析与实战指南

5个步骤让电脑风扇彻底静音&#xff1a;FanControl深度解析与实战指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trendin…...

AElf节点运维实战:从部署监控到故障排查的完整指南

1. 项目概述与核心价值 最近在梳理区块链节点运维和性能调优的实践时&#xff0c;我重新审视了AElf生态中的一个宝藏项目—— aelf-node-skill 。这并非一个独立的区块链应用或智能合约&#xff0c;而是一个专门为AElf节点运维工程师和开发者准备的“技能包”或“工具箱”。简…...

告别手动分层:layerdivider如何用AI将图像编辑效率提升90%

告别手动分层&#xff1a;layerdivider如何用AI将图像编辑效率提升90% 【免费下载链接】layerdivider A tool to divide a single illustration into a layered structure. 项目地址: https://gitcode.com/gh_mirrors/la/layerdivider 你是否曾为了一张复杂的插画作品&a…...

MobilityBench:智能交通路线规划算法的真实场景测试基准

1. 项目背景与核心价值在智能交通和自动驾驶领域&#xff0c;路线规划算法的性能评估一直是个棘手问题。传统测试方法往往依赖仿真环境或固定数据集&#xff0c;难以反映算法在真实世界复杂场景中的表现。这正是MobilityBench试图解决的痛点——它构建了一个贴近现实的测试基准…...

基于Godot引擎的2D ARPG框架:模块化设计与实战开发指南

1. 项目概述&#xff1a;一个基于Godot引擎的2D地下城动作游戏框架最近在独立游戏开发圈里&#xff0c;一个名为“UnderworldGodot”的开源项目引起了我的注意。这个由开发者hankmorgan创建的项目&#xff0c;本质上是一个为Godot 4引擎量身打造的、功能完备的2D动作角色扮演游…...

MosaicMem:视频预测中的记忆模块创新与应用

1. 项目概述&#xff1a;当视频生成遇见记忆模块去年在调试一个视频预测模型时&#xff0c;我发现传统方法对长序列的时空一致性处理总是差强人意——要么丢失细节&#xff0c;要么出现断层式跳变。这促使我开始探索如何将人类记忆的"碎片化重组"特性引入深度学习框架…...

AI应用的幂等性工程2026:让LLM任务在失败重试时不出错

LLM应用在生产环境中面临着普通软件没有的挑战&#xff1a;同一个任务被重复执行时&#xff0c;可能产生副作用&#xff08;发两次邮件、创建重复记录、扣两次款&#xff09;。幂等性设计是解决这个问题的工程答案。 —## 问题的本质&#xff1a;LLM应用的非确定性传统软件的幂…...

Dify 1.0工程实践:开源LLM应用开发平台的生产级部署完全指南

Dify在2026年发布1.0正式版后&#xff0c;成为中小团队构建AI应用的首选平台。本文从生产部署、自定义开发到API集成&#xff0c;全面解析Dify在企业环境中的落地方案。 —## 为什么选择Dify在AI应用开发领域&#xff0c;有两条路&#xff1a;1. 从零用SDK构建&#xff1a;灵活…...

智慧矿山井下灾害预警模块AI视觉解决方案

井下一声巨响&#xff0c;不仅矿灯在晃&#xff0c;人心更在抖。老王在煤矿干了二十年安检员&#xff0c;他最怕的不是明火&#xff0c;而是那团似有似无的“青烟”和巷道壁上像蛛网一样的细纹。用他的话说&#xff1a;“井下环境太复杂&#xff0c;灯光暗、水汽大&#xff0c;…...

Cursor与Claude Code深度对比2026:两大AI编程工具的工程师实战测评

2026年&#xff0c;AI编程助手进入"重度依赖"时代。Cursor依然强劲&#xff0c;而Anthropic推出的Claude Code正在改写规则。本文从工程师视角&#xff0c;对比两款工具在真实项目中的表现&#xff0c;帮你决定该用哪个——或者怎么搭配使用。 —## 背景&#xff1a;…...

大模型上下文压缩工程2026:让100K Token的信息塞进4K窗口

超长上下文固然好&#xff0c;但它带来高成本、高延迟和注意力稀释问题。本文深入探讨如何通过智能压缩技术&#xff0c;在有限上下文窗口内保留最大信息量&#xff0c;实现质量与效率的最优平衡。 —## 上下文窗口的本质矛盾表面上看&#xff0c;模型支持的上下文窗口越来越大…...