diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index ac984d1a..53b57fd5 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -28,7 +28,7 @@ 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 -# 思路 +## 思路 本题是KMP 经典题目。 @@ -60,13 +60,13 @@ KMP的经典思想就是:**当出现字符串不匹配时,可以记录一部 读完本篇可以顺便把leetcode上28.实现strStr()题目做了。 -# 什么是KMP +### 什么是KMP 说到KMP,先说一下KMP这个名字是怎么来的,为什么叫做KMP呢。 因为是由这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP -# KMP有什么用 +### KMP有什么用 KMP主要应用在字符串匹配上。 @@ -84,7 +84,7 @@ KMP的主要思想是**当出现字符串不匹配时,可以知道一部分之 下面Carl就带大家把KMP的精髓,next数组弄清楚。 -# 什么是前缀表 +### 什么是前缀表 写过KMP的同学,一定都写过next数组,那么这个next数组究竟是个啥呢? @@ -122,7 +122,7 @@ next数组就是一个前缀表(prefix table)。 那么什么是前缀表:**记录下标i之前(包括i)的字符串中,有多大长度的相同前缀后缀。** -# 最长公共前后缀? +### 最长公共前后缀 文章中字符串的**前缀是指不包含最后一个字符的所有以第一个字符开头的连续子串**。 @@ -144,7 +144,7 @@ next数组就是一个前缀表(prefix table)。 等等.....。 -# 为什么一定要用前缀表 +### 为什么一定要用前缀表 这就是前缀表,那为啥就能告诉我们 上次匹配的位置,并跳过去呢? @@ -163,7 +163,7 @@ next数组就是一个前缀表(prefix table)。 **很多介绍KMP的文章或者视频并没有把为什么要用前缀表?这个问题说清楚,而是直接默认使用前缀表。** -# 如何计算前缀表 +### 如何计算前缀表 接下来就要说一说怎么计算前缀表。 @@ -205,7 +205,7 @@ next数组就是一个前缀表(prefix table)。 最后就在文本串中找到了和模式串匹配的子串了。 -# 前缀表与next数组 +### 前缀表与next数组 很多KMP算法的时间都是使用next数组来做回退操作,那么next数组与前缀表有什么关系呢? @@ -217,7 +217,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减 后面我会提供两种不同的实现代码,大家就明白了。 -# 使用next数组来匹配 +### 使用next数组来匹配 **以下我们以前缀表统一减一之后的next数组来做演示**。 @@ -229,7 +229,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减 ![KMP精讲4](https://code-thinking.cdn.bcebos.com/gifs/KMP%E7%B2%BE%E8%AE%B24.gif) -# 时间复杂度分析 +### 时间复杂度分析 其中n为文本串长度,m为模式串长度,因为在匹配的过程中,根据前缀表不断调整匹配的位置,可以看出匹配的过程是O(n),之前还要单独生成next数组,时间复杂度是O(m)。所以整个KMP算法的时间复杂度是O(n+m)的。 @@ -239,7 +239,7 @@ next数组就可以是前缀表,但是很多实现都是把前缀表统一减 都知道使用KMP算法,一定要构造next数组。 -# 构造next数组 +### 构造next数组 我们定义一个函数getNext来构建next数组,函数参数为指向next数组的指针,和一个字符串。 代码如下: @@ -338,7 +338,7 @@ void getNext(int* next, const string& s){ 得到了next数组之后,就要用这个来做匹配了。 -# 使用next数组来做匹配 +### 使用next数组来做匹配 在文本串s里 找是否出现过模式串t。 @@ -403,7 +403,7 @@ for (int i = 0; i < s.size(); i++) { // 注意i就从0开始 此时所有逻辑的代码都已经写出来了,力扣 28.实现strStr 题目的整体代码如下: -# 前缀表统一减一 C++代码实现 +### 前缀表统一减一 C++代码实现 ```CPP class Solution { @@ -447,7 +447,7 @@ public: * 时间复杂度: O(n + m) * 空间复杂度: O(m), 只需要保存字符串needle的前缀表 -# 前缀表(不减一)C++实现 +### 前缀表(不减一)C++实现 那么前缀表就不减一了,也不右移的,到底行不行呢? @@ -546,7 +546,7 @@ public: * 空间复杂度: O(m) -# 总结 +## 总结 我们介绍了什么是KMP,KMP可以解决什么问题,然后分析KMP算法里的next数组,知道了next数组就是前缀表,再分析为什么要是前缀表而不是什么其他表。 @@ -563,8 +563,7 @@ public: ## 其他语言版本 - -Java: +### Java: ```Java class Solution { @@ -691,8 +690,9 @@ class Solution { } ``` -Python3: +### Python3: (版本一)前缀表(减一) + ```python class Solution: def getNext(self, next, s): @@ -781,9 +781,9 @@ class Solution: def strStr(self, haystack: str, needle: str) -> int: return haystack.find(needle) -``` +``` -Go: +### Go: ```go // 方法一:前缀表使用减1实现 @@ -871,7 +871,7 @@ func strStr(haystack string, needle string) int { } ``` -JavaScript版本 +### JavaScript: > 前缀表统一减一 @@ -959,7 +959,7 @@ var strStr = function (haystack, needle) { }; ``` -TypeScript版本: +### TypeScript: > 前缀表统一减一 @@ -1036,7 +1036,7 @@ function strStr(haystack: string, needle: string): number { } ``` -Swift 版本 +### Swift: > 前缀表统一减一 @@ -1196,7 +1196,7 @@ func strStr(_ haystack: String, _ needle: String) -> Int { ``` -PHP: +### PHP: > 前缀表统一减一 ```php @@ -1272,7 +1272,7 @@ function getNext(&$next, $s){ } ``` -Rust: +### Rust: > 前缀表统一不减一 ```Rust @@ -1362,4 +1362,3 @@ impl Solution { -