【普通解法】从左到右遍历str1的每一个字符,然后看如果 以当前字符作为第一个字符出发 是否匹配 str2字符串。

【KMP算法】

1)生成一个nextArr数组,长度与str2字符串长度一样。i 的 值 含义是 str[0 - i-1】中,必须以str[i-1] 结尾的后缀子串 与 必须以 str[0]开头的前缀子串,最大匹配长度是多少。

快速生成 nextArr数组,先等等

2)



假设 str1 从 i 到 j - 1 和 str2 从 0 到 j-1一样。从j不一样了。

然后str2的索引退回到 t2 索引 继续 和 str1的 j匹配。 圆圈就代表 最长前缀子串。

str1 索引不回退,是因为 中间其他位置不可能再完全匹配 str2了。

使用反证法:



假设str1 能从 k开始能够完全 匹配 str2. 看虚线部分。

说明 虚线1 和 虚线2 一样。

又因为str1 和 str2 从 0 到 j-1 一样。说明 虚线 1 和 虚线 3 一样。

那么 虚线2 和虚线3 一样,那么最长前缀子串 就不是咱开始的了。

如果咱的最长子串 算的是对的,那么 str1索引从j开始就没问题。

【nextArr数组生成】

1)从左到右依次求解。

在 求解到 i的时候, 0 到 i-1的值已经求出来了。

计算i的时候,已经知道i-1的最长前缀 A 和 最长后缀 B的匹配区域, A=B

然后判断 A区域下一个 t1位置的值 和B区域下一个 t2位置 的 值 ,也就是 i-1位置的值,俩个是否相等。

如果相等: 那么 nextArr[i] 的值就是 nextArr[i-1]的值加1.



如果不相等: 那么继续往回跳。看t1字符之前的 前缀 和 后缀的匹配情况。 判断 t3 和 t2是否相等。

A 和 B相等,t1的前缀 A1 和 t1的后缀 A2相等, A1=A2

A=B。 B1=B2 .那么 A1=B2.

直到 t1的最长前后缀为0 结束。开始下一个位置的计算。

java实现:

public class KMP {

    public static int getIndexOf(String str1, String str2) {

        if (str1 == null || str2 == null || str2.length() < 1 || str1.length() < str2.length()) {
return -1; }
char[] str1_arr = str1.toCharArray();
char[] str2_arr = str2.toCharArray(); int str1_length = str1_arr.length;
int str2_length = str2_arr.length; int[] nextArr = getNextArr(str2); int str1_index = 0;
int str2_index = 0;
// 循环终止条件。 str1_index 越界 或者 str2_index 越界
// str1_index 越界,str2_index没越界,说明没匹配到
// str1_index 不越界,str2_index 越界, 说明匹配到了
// str1_index 和 str2_index一起越界。 也匹配到了。
while (str1_index < str1_length && str2_index < str2_length) { if (str1_arr[str1_index] == str2_arr[str2_index]) {
// 一样。都向右走
str1_index++;
str2_index++;
} else if (nextArr[str2_index] == -1) {
// 说明 str2 往回退到 起点了。 等价 str2_index == 0
// str1 继续往右走就好。
str1_index++;
} else {
// str2 指针往回退, nextArr[str2_index]
str2_index = nextArr[str2_index];
}
}
// 如果str_length == str2_index ,说明匹配到了。
// str1_index - str2_index 就是 匹配到的起始位置。
return str2_length == str2_index ? str1_index - str2_index : -1;
} public static int[] getNextArr(String str) { char[] str_arr = str.toCharArray();
if (str_arr.length == 1) {
return new int[] { -1 };
}
int[] nextArr = new int[str_arr.length]; nextArr[0] = -1; // 起始位置 记为 -1.好判断。
nextArr[1] = 0; // 1 的前缀后缀不存在,所以是0 int current_index = 2; // 从2 开始
int pre_pos_value = 0; // 保存当前的最长前缀 后缀的长度。开始从2 计算。nextArr[1] 就是0 。 while (current_index < str_arr.length) {
if (str_arr[current_index - 1] == str_arr[pre_pos_value]) {
// 比较的字符不相等,比较的后一个字符永远是 current_index -1 的位置
nextArr[current_index] = pre_pos_value + 1; // t1 和 t2 的值相等。那么 current_index就是前面 的nextArr[]值 + 1
current_index++; // 继续下一个。
} else if (pre_pos_value > 0) {
// 比较的字符不相等,比较的后一个字符永远是 current_index -1 的位置
// 比较的字符不相等,那么就看 t1 的 pre_pos_value. pre_pos_value 是从0开始的。这个是个很重要的信息。是长度,也是索引。
// A1区域的最长前缀 后缀 不为 0 。
pre_pos_value = nextArr[pre_pos_value];
} else {
// 比较的字符不相等,比较的后一个字符永远是 current_index -1 的位置
// 往回跳,A1区域的最长前缀 后缀 已经为 0 。。不存在最长前后缀了。
nextArr[current_index] = 0;
// 然后可以计算下一个了
current_index++;
}
}
return nextArr;
} public static void main(String[] args) {
String str = "abcabcababaccc";
String match = "ababa";
System.out.println(getIndexOf(str, match)); } }

明天再用python实现吧。

python 忘记 对 最长前后缀 增加 1 了。

python 初始化数组之后,使用append新增。

# coding: utf-8

def kmp(str1, str2):

    str1_index = 0
str2_index = 0
next_arr = get_next_arr(str2)
print(f"next_arr{next_arr}")
while str1_index < len(str1) and str2_index < len(str2): if str1[str1_index] == str2[str2_index]:
# 字符一样
str1_index += 1
str2_index += 1
elif next_arr[str2_index] == -1:
# str2往回跳到 位置0 了
str1_index += 1
else:
str2_index = next_arr[str2_index] print(str2_index)
print(str1_index)
if str2_index == len(str2):
return str1_index - str2_index
else:
return -1 def get_next_arr(str2):
next_arr = [-1, 0]
cur_index = 2
pre_pos_value = 0 while cur_index < len(str2):
if str2[cur_index-1] == str2[pre_pos_value]:
# t1 == t2
next_arr.append(pre_pos_value + 1)
cur_index += 1
pre_pos_value += 1 # 忘记对pre_pos_value进行增加了。
elif pre_pos_value > 0:
# t1往回跳
pre_pos_value = next_arr[pre_pos_value]
else:
# 最长前缀为0.
next_arr.append(0)
cur_index += 1 return next_arr str1 = "abcabcababaccc"
str2 = "ababa" print(kmp(str1,str2))

算法:KMP, str1字符串是否包含str2字符串的更多相关文章

  1. 算法之暴力破解和kmp算法 判断A字符串是否包含B字符串

    我们都知道java中有封装好的方法,用来比较A字符串是否包含B字符串 如下代码,contains,用法是 str1.contains(str2), 这个布尔型返回,存在返回true,不存在返回fals ...

  2. EL表达式处理字符串 是否 包含 某字符串 截取 拆分...............

    EL表达式处理字符串 是否 包含 某字符串 截取 拆分............... JSP页面页头添加<%@ taglib uri="/WEB-INF/taglib/c.tld&qu ...

  3. 【功能代码】---3 JS判断字符串是否包含某个字符串

    JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...

  4. mysql判断表里面一个逗号分隔的字符串是否包含单个字符串、查询结果用逗号分隔

    1.mysql判断表里面一个逗号分隔的字符串是否包含单个字符串 : FIND_IN_SET select * from tablename where FIND_IN_SET(传的参数,匹配字段) 例 ...

  5. 如何在 JavaScript 中检查字符串是否包含子字符串?

    如何在 JavaScript 中检查字符串是否包含子字符串? // var test4 = _.includes(string, substring); 该方法需要此文件 <script src ...

  6. C/C++判断字符串是否包含某个字符串

    C风格 #include <iostream> #include <string> #include <cstring> using namespace std; ...

  7. js 判断字符串是否包含某字符串,String对象中查找子字符,indexOf

    var Cts = "bblText";   if(Cts.indexOf("Text") > 0 ) {     alert('Cts中包含Text字符 ...

  8. 【Java】判断字符串是否包含子字符串

    JAVA里面判断: public static void main(String[] args) { String str="ABC_001"; if(str.indexOf(&q ...

  9. [转载]js javascript 判断字符串是否包含某字符串,String对象中查找子字符,indexOf

    var Cts = "bblText"; if(Cts.indexOf("Text") > 0 ) { alert('Cts中包含Text字符串'); }

随机推荐

  1. Gitlab分支策略建议指南

    本文分支策略为总结各中小型企业常见做法(仅代表个人观点),在下才疏学浅,文章如有缺漏或不当之处,望各位帮忙指正.写此文也十分希望能起抛砖引玉之效. 据我所知,目前大部分无论是按瀑布/敏捷开发模型,就算 ...

  2. 【docker专栏5】详解docker镜像管理命令

    一.国内Docker镜像仓库 由于大家都知道的原因,从国外的docker 仓库中pull镜像的下载速度实际上是很慢的.国内的一些一线厂商以及docker官方都在国内免费提供了一些docker镜像仓库, ...

  3. CF222C Reducing Fractions

    题目大意: 给出两个集合,第一个集合数的乘积是分子,第二个集合的数的乘积是分母,要求够造一个同样的集合,但是得到的分数是最简分数. 分析: 寻找思路并不复杂,对两个集合的每个数进行质因数分解,然后统计 ...

  4. 如何创建一个带诊断工具的.NET镜像

    现阶段的问题 现在是云原生和容器化时代,.NET Core对于云原生来说有非常好的兼容和亲和性,dotnet社区以及微软为.NET Core提供了非常方便的镜像容器化方案.所以现在大多数的dotnet ...

  5. 从零开始实现lmax-Disruptor队列(六)Disruptor 解决伪共享、消费者优雅停止实现原理解析

    MyDisruptor V6版本介绍 在v5版本的MyDisruptor实现DSL风格的API后.按照计划,v6版本的MyDisruptor作为最后一个版本,需要对MyDisruptor进行最终的一些 ...

  6. Rust 从入门到精通03-helloworld

    安装完成 Rust 之后,我们可以编写 Rust 的 Hello Word.这里介绍两种方式,一种是rust原生方式,一种是利用 cargo 工具(重要) 1.rustc 方式 1.1 创建项目目录 ...

  7. 技术分享 | ARM下中标麒麟系统ky10使用Xtrabackup-8.0.25

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 一.需求背景 查询Percona官方手册,Xtrabackup 8.0可以备份M ...

  8. Luogu3802 小魔女帕琪 (排列组合)

    注意除数为0情况 #include <iostream> #include <cstdio> #include <cstring> #include <alg ...

  9. ESP32与MicroPython入门-01 搭建开发环境

    ESP32简介 ESP32 是上海乐鑫公司开发的一款比较新的32位微控制器,它集成了WiFi及蓝牙等功能,有着性能稳定.功耗低.价格低廉等特点,非常适用于物联网开发,但也可以作为普通的MCU使用. E ...

  10. Web 前端实战:Gitee 贡献图

    前言 这次要做的 Web 前端实战是一个 Gitee 个人主页下的贡献图(在线 Demo),偶尔做一两个,熟悉熟悉 JS 以及 jQ.整体来说这个案例并不难,主要是控制第一个节点以及最后一个节点处于星 ...