今天中午一觉睡醒,刷b站,看见一个视频:

最浅显易懂的 KMP 算法讲解https://www.bilibili.com/video/BV1AY4y157yL?spm_id_from=333.1007.top_right_bar_window_history.content.click

虽然他是用python写的,代码我只能看懂一点点,但是知道思想就能自己实现了。恰恰好,今天是周日,我这周的博客还没写,就来小小的码一下吧。

暴力解析

首先是暴力解析法,就是遍历源字符串的每一个字符,如果和目标字符串的首字符匹配了,就比较下一位字符,如果匹配到了就返回第一个字符的下标,如果没有匹配到就回到第一个字符的后一位继续比较,实现代码:

    /*** 暴力解析获取子串第一次出现的位置* @param src 源字符串* @param target 目标字符串* @return 如果目标串出现了返回目标串第一次出现的起始下标,目标串不存在返回-1*/public static int violenceAnalysis(String src,String target){//目标字符串的长度int targetLength = target.length();//遍历源字符串,获取起始下标,当起始下标后的字符串长度比目标串短,就不可能匹配到了for (int srcIndex = 0; srcIndex < src.length() - targetLength + 1; srcIndex++){//如果首字符都不相同就不需要比较了if (src.charAt(srcIndex) != target.charAt(0)){continue;}//如果目标字符串长度为1,返回当前下标if (targetLength == 1){return srcIndex;}//临时下标,用于对比后面的字符是否相同int tempSrcIndex = srcIndex + 1;//对比目标字符串和源字符串后续字符for (int targetIndex = 1; targetIndex < targetLength; targetIndex++){//不相同就结束对比if (src.charAt(tempSrcIndex++) != target.charAt(targetIndex)){break;}//对比到目标字符串最后一个字符,说明匹配到子串了if (targetIndex == targetLength - 1){return srcIndex;}}}//结束对比还没有找到,返回-1return -1;}

这种方法需要不断回溯,非常耗时。

KMP

kmp算法需要一个next数组,这个数组记录了目标字符串target的每一位与开头相比相同的字符数,如“123123”的next数组是[0,0,0,1,2,3],"ACDABCAC"的next数组是[0,0,0,1,0,0,1,2]。

我们从头遍历源字符串src,如果与target的首字符相同就向后比较,在比较过程中如果发现不相同不需要跟暴力解析一样吧src的下标回溯到起始位置的下一位,只需要使target下标等于next数组中找到与target最后一位匹配上的字符串相同下标的数据,如target是"ACDABCAC"匹配到了B发现不同了,我们只需要将target下标赋值为1就行了。然后继续向后比较。说起来很复杂,直接上代码:

    /*** 获取next数组* @param target 需要获取next数组的字符串* @return 返回next数组*/public static int[] getNextArray(String target){//res数组长度与target一样//每个位置记录的是target对应位置上字符与target开头匹配了几位int[] res = new int[target.length()];//第一个字符为0,因为没有字符跟它匹配res[0] = 0;for (int i = 1; i < target.length(); i++){//target.charAt(i)是当前字符//target.charAt(res[i - 1])是当前匹配到了开头往后第几个字符//如果相同,匹配成功,当前下标等于前一个下标+1if (target.charAt(i) == target.charAt(res[i - 1])){res[i] = res[i - 1] + 1;}else{//当前字符与首字符相同,重新开始皮皮额if (target.charAt(0) == target.charAt(i)){res[i] = 1;}else{//与首字符不相同置为0res[i] = 0;}}}return res;}/*** 使用kmp算法来查找目标串出现的位置* @param src 源串* @param target 目标串* @return 如果目标串存在返回第一次出现的位置,反之返回-1*/public static int kmp(String src,String target){//获取next数组int[] next = getNextArray(target);//目标串下标int targetIndex = 0;//对比for (int srcIndex = 0; srcIndex < src.length(); srcIndex++){//如果匹配,目标串下标+1if (src.charAt(srcIndex) == target.charAt(targetIndex)){if (target.length() == 1){return srcIndex;}targetIndex++;//如果下标大于目标串长度,匹配完成if (targetIndex == target.length()){return srcIndex - target.length() + 1;}}else{//如果不匹配则目标串下标回溯到next数组中最后一个匹配字符对应的数targetIndex = next[targetIndex];}}//遍历结束都没有找到,返回-1return -1;}

这个算法只需要遍历一次src数组。

结果

测试一下,随机生成一个很长的字符串,然后在里面查找"1a1a1a1a":

    public static void main(String[] args) {Random random = new Random();StringBuilder sb = new StringBuilder();for (int i = 0; i < 0x11EFFFFF; i++){sb.append((char)(random.nextInt('z' - '0') + '0'));}String src = sb.toString();String target = "1a1a1a1a";long start1 = System.currentTimeMillis();System.out.println(violenceAnalysis(src,target));long end1 = System.currentTimeMillis();long start2 = System.currentTimeMillis();System.out.println(kmp(src,target));long end2 = System.currentTimeMillis();System.out.println("暴力解析用时:" + (end1 - start1));System.out.println("kmp用时:" + (end2 - start2));}

运行截图

kmp确实比暴力解析要快

在字符串中查找子字符串相关推荐

  1. Python在字符串中查找子字符串

    这是小白博主在刷leetcode时遇到的一道题,这是博主近日刷的leetcode题库时结果表现最好的一道题,故在此分享这份喜悦. 希望在以后的日子里可以继续进步,持之以恒. 目录 题目介绍 解题思路及 ...

  2. 在Python中查找子字符串索引的5种方法

    在Python中查找字符串中子字符串索引的5种方法 (5 Ways to Find the Index of a Substring in Strings in Python) str.find() ...

  3. javascript 字符串中查找指定字符串

    在javascript中,有以下三个方法均可实现在字符串中查找指定的字符及字符串. str.indexOf(); 此方法:查找字符在字符串对象中第一次出现的位置.存在,则返回字符串所在的位置.不存在, ...

  4. C语言strchr()函数(字符串中查找子字符)

    头文件:C 标准库 - <string.h> 描述 C 库函数 char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 ...

  5. java查找字符串中包含子字符串的个数,灵活运用String方法,3种方法的代码实现!

    第一种方法: 灵活运用split方法!直接把子字符串作为split的参数传进去,看看原字符串被分割成了几部分,得到的String数组的length.然后length - 1就是 需要查询的子字符串的个 ...

  6. C语言strstr()函数(在主字符串里查找子字符串,返回第一次找到的子字符串以及后面的字符串)

    需包含头文件:C 标准库 - <string.h> 文章目录 描述 声明 参数 返回值 实例 描述 C 库函数 char *strstr(const char *haystack, con ...

  7. python取字符串一部分_python,如何获取字符串中的子字符串,部分字符串

    说明: 比如有一个字符串,python,如何就获取前3位,或者后2位.在此记录下. 操作过程: 1.通过分割符的方式,下标的方式,获取字符串中的子串 >>> text = 'pyth ...

  8. 在字符串中查找指定字符串

    package six; import java.util.*; public class Demo {static Scanner sc = new Scanner(System.in);publi ...

  9. 字符串的匹配搜索,在主字符串中搜寻子字符串,并给出此子字符串的起始位置,否则找不到

    #include<stdio.h> #include<stdlib.h> int main() {int i, j, temp;char str[100], substr[20 ...

最新文章

  1. 前端实时刷新数据_产品又让我造数据
  2. 当机器学习性能遭遇瓶颈时,如何优化?如何去尝试解决问题?
  3. 刚刚,谷歌终于回应AI专利争议:怕被碰瓷,抢先下手,永不牟利
  4. 2.1.2 何为真值,何为机器数?
  5. J-Link该如何升级固件?
  6. 解决VMware卸载后再安装出现的问题
  7. lisp如何将度分秒转换为弧度_1/16怎么转换成角度(度分秒)??
  8. 摄影测量空间后方交会外方位元素的解算程序
  9. 如何在R里面安装做gif动图的gganimate包
  10. 家庭问题(信息学奥赛一本通 - T1362)
  11. .NET6东西--可写的JSON DOM API
  12. HTTPS为什么安全
  13. 蓝桥杯练习 数的读法
  14. 兴趣社区圈子论坛系统搭建教程,教你上线自己的论坛圈子系统。
  15. 解决vue的跨域问题
  16. 职业篇-忠告1-把工作当做实现人生价值的阶梯
  17. Linux防火墙常用命令
  18. 丝绸之路翻译软件测试,域渗透测试指南之GPO和OU详解(下)
  19. Analog Devices AD1983 @ 英特尔 82801H(ICH8) 高保真音频
  20. 移动用户最爱视频播放、电商导购、新闻阅读

热门文章

  1. ALEVEL经济知识点讲解:政府对市场的干预
  2. 【5000字长文】从 S3 到 DataZone,亚马逊云科技用16年讲完一个数据的故事
  3. jsp物流信息发布管理平台
  4. 你知道如何修改单选框、复选框、下拉框的默认样式吗
  5. 网卡链路聚合之team
  6. 复盘:智能座舱系列文六- 它的3种交互方式之显式交互(语音以及显示)
  7. Jenkins整合dingding json pusher,发送自定义消息到钉钉群
  8. 《THE BASIC GRAMMER OF C》
  9. 二分查找算法(递归+非递归)
  10. 计算机毕设(附源码)JAVA-SSM基于智慧农业的水果销售系统