22## 题目地址   
33https://leetcode-cn.com/problems/implement-strstr/ 
44
5- ## 思路   
5+ >  在一个串中查找是否出现过另一个串,这是KMP的看家本领。 
6+ 
7+ # 题目:28. 实现 strStr()   
8+ 
9+ 实现 strStr() 函数。
10+ 
11+ 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回  -1。
12+ 
13+ 示例 1: 
14+ 输入: haystack = "hello", needle = "ll" 
15+ 输出: 2 
16+ 
17+ 示例 2: 
18+ 输入: haystack = "aaaaa", needle = "bba" 
19+ 输出: -1 
20+ 
21+ 说明: 
22+ 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 
23+ 对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。 
24+ 
25+ 
26+ # 思路   
627
728本题是KMP 经典题目。
829
930KMP的经典思想就是:** 当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。** 
1031
11- 如果对KMP理论基础还不够了解的同学请看[ ] ( ) 
32+ 如果对KMP理论基础还不够了解的同学请看[ 字符串:KMP是时候上场了(一文读懂系列) ] ( https://mp.weixin.qq.com/s/70OXnZ4Ez29CKRrUpVJmug ) 。  
1233
13- 定义一个函数getNext来构建next数组, 函数参数为指向next数组的指针,和一个字符串。 然后在函数里完成对next数组的构建。 
34+ ** 为了和 [ 字符串:KMP是时候上场了(一文读懂系列) ] ( https://mp.weixin.qq.com/s/70OXnZ4Ez29CKRrUpVJmug ) 字符串命名统一,方便大家理解,以下文章统称haystack为文本串, needle为模式串。 ** 
1435
36+ 都知道使用KMP算法,一定要构造next数组。
1537
16- 这其实就是计算模式串s,前缀表的过程。 主要有如下三步:
38+ # 构造next数组  
39+ 
40+ 我们定义一个函数getNext来构建next数组,函数参数为指向next数组的指针,和一个字符串。 代码如下:
41+ 
42+ ``` 
43+ void getNext(int* next, const string& s) 
44+ ``` 
45+ 
46+ ** 构造next数组其实就是计算模式串s,前缀表的过程。**  主要有如下三步:
1747
18481 .  初始化
19492 .  处理前后缀不相同的情况
20503 .  处理前后缀相同的情况
2151
52+ 接下来我们详解详解一下。
53+ 
22541 .  初始化:
2355
2456定义两个指针i和j,j指向前缀终止位置(严格来说是终止位置减一的位置),i指向后缀终止位置(与j同理)。
2557
2658然后还要对next数组进行初始化赋值,如下:
2759
2860``` 
29-          int j = -1;
30-          next[0] = j;
61+ int j = -1; 
62+ next[0] = j; 
3163``` 
3264
3365j 为什么要初始化为 -1呢,因为之前说过 前缀表要统一减一的操作,所以j初始化为-1。
@@ -45,7 +77,7 @@ next[i] 表示 i(包括i)之前最长相等的前后缀长度(其实就是
4577所以遍历模式串s的循环下表i 要从 1开始,代码如下:
4678
4779``` 
48-          for(int i = 1; i < s.size(); i++) {
80+ for(int i = 1; i < s.size(); i++) { 
4981``` 
5082
5183如果 s[ i]  与 s[ j+1] 不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回溯。
@@ -80,29 +112,31 @@ next[i] = j;
80112最后整体构建next数组的函数代码如下:
81113
82114``` 
83-     void getNext(int* next, const string& s){ 
84-         int j = -1; 
85-         next[0] = j; 
86-         for(int i = 1; i < s.size(); i++) { // 注意i从1开始 
87-             while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了 
88-                 j = next[j]; // 向前回溯 
89-             } 
90-             if (s[i] == s[j + 1]) { // 找到相同的前后缀 
91-                 j++; 
92-             } 
93-             next[i] = j; // 将j(前缀的长度)赋给next[i] 
115+ void getNext(int* next, const string& s){ 
116+     int j = -1; 
117+     next[0] = j; 
118+     for(int i = 1; i < s.size(); i++) { // 注意i从1开始 
119+         while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了 
120+             j = next[j]; // 向前回溯 
94121        } 
122+         if (s[i] == s[j + 1]) { // 找到相同的前后缀 
123+             j++; 
124+         } 
125+         next[i] = j; // 将j(前缀的长度)赋给next[i] 
95126    } 
127+ } 
96128``` 
97129
98130
99- 代码构造next数组的逻辑流程如下 :
131+ 代码构造next数组的逻辑流程动画如下 :
100132
101133<img  src =' ../../media/video/KMP精讲3.gif '  width =600 > </img ></div >
102134
103135
104136得到了next数组之后,就要用这个来做匹配了。
105137
138+ # 使用next数组来做匹配  
139+ 
106140在文本串s里 找是否出现过模式串t。
107141
108142定义两个下表j 指向模式串起始位置,i指向文本串其实位置。
@@ -150,67 +184,62 @@ if (j == (t.size() - 1) ) {
150184那么使用next数组,用模式串匹配文本串的整体代码如下:
151185
152186``` 
153-          int j = -1; // 因为next数组里记录的起始位置为-1
154-          for (int i = 0; i < s.size(); i++) { // 注意i就从0开始
155-              while(j >= 0 && s[i] != t[j + 1]) { // 不匹配 
156-                  j = next[j]; // j 寻找之前匹配的位置 
157-              } 
158-              if (s[i] == t[j + 1]) { // 匹配,j和i同时向后移动 
159-                  j++; // i的增加在for循环里 
160-              } 
161-              if (j == (t.size() - 1) ) { // 文本串s里出现了模式串t 
162-                  return (i - t.size() + 1); 
163-              } 
164-          }
187+ int j = -1; // 因为next数组里记录的起始位置为-1 
188+ for (int i = 0; i < s.size(); i++) { // 注意i就从0开始 
189+     while(j >= 0 && s[i] != t[j + 1]) { // 不匹配 
190+         j = next[j]; // j 寻找之前匹配的位置 
191+     } 
192+     if (s[i] == t[j + 1]) { // 匹配,j和i同时向后移动 
193+         j++; // i的增加在for循环里 
194+     } 
195+     if (j == (t.size() - 1) ) { // 文本串s里出现了模式串t 
196+         return (i - t.size() + 1); 
197+     } 
198+ } 
165199``` 
166200
167201此时所有逻辑的代码都已经写出来了,本题整体代码如下:
168202
169- 
170- 
171- 
172- 
173203## C++代码  
174204
175205``` 
176206class Solution { 
177207public: 
178-   void  getNext(int*  next,  const  string& s) {
179-  next[0] =  -1;
180-  int j = -1 ;
181-   for(int i = 1; i <  s.size();  i++){ 
182-   while (j >= 0 &&  s[i] !=  s[j +  1]) { 
183-  j =  next[j];
184-   }
185-  if  (s[i] ==  s[j +  1]) { 
186-   j++;
187-   }
188-   next[i] = j; 
189-   }
190-   }
208+      void  getNext(int*  next,  const  string& s)  {
209+         int j =  -1;
210+         next[0] = j ;
211+          for(int i = 1; i <  s.size();  i++) { // 注意i从1开始 
212+              while (j >= 0 &&  s[i] !=  s[j +  1]) { // 前后缀不相同了 
213+                 j =  next[j]; // 向前回溯 
214+              }
215+             if  (s[i] ==  s[j +  1]) { // 找到相同的前后缀 
216+                  j++;
217+              }
218+              next[i] = j; // 将j(前缀的长度)赋给next[i] 
219+          }
220+      }
191221 int strStr(string haystack, string needle) { 
192222 if (needle.size() == 0) { 
193223 return 0; 
194224 } 
195225 int next[needle.size()]; 
196226 getNext(next, needle); 
197- 
198-  int j = -1; 
199-  for (int i = 0; i < haystack.size(); i++) { 
200-  while(j >= 0 && haystack[i] != needle[j + 1]) { 
201-  j = next[j]; 
227+  int j = -1; // // 因为next数组里记录的起始位置为-1 
228+  for (int i = 0; i < haystack.size(); i++) { // 注意i就从0开始 
229+  while(j >= 0 && haystack[i] != needle[j + 1]) { // 不匹配 
230+  j = next[j]; // j 寻找之前匹配的位置 
202231 } 
203-  if (haystack[i] == needle[j + 1]) { 
204-  j++; 
232+  if (haystack[i] == needle[j + 1]) { // 匹配,j和i同时向后移动   
233+  j++; // i的增加在for循环里  
205234 } 
206-  if (j == (needle.size() - 1) ) { 
207-  return (i - needle.size() + 1); 
235+  if (j == (needle.size() - 1) ) { // 文本串s里出现了模式串t  
236+  return (i - needle.size() + 1);   
208237 } 
209238 } 
210239 return -1; 
211240 } 
212241}; 
213242
214243``` 
215- >  更过算法干货文章持续更新 ,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
244+ >  更多算法干货文章持续更新 ,可以微信搜索「代码随想录」第一时间围观,关注后,回复「Java」「C++」 「python」「简历模板」「数据结构与算法」等等,就可以获得我多年整理的学习资料。
216245
0 commit comments