Implement strStr().
Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
解题:
本题为典型的KMP算法考察题,KMP算法描述为:
设主串S,匹配串P,i为S的索引下标,j为P的索引下标,初始i和j设置为0。
在i小于S的长度和j小于P的长度时,开始循环:
1、比较S[i]和P[j]是否相同;
2、如果相同则i++,j++,返回执行第1步;
3、如果不同,则计算已匹配成功的P[0]~P[j-1]中,相同前缀和后缀的最大长度,设为n;
4、令i不变,j为n(指向相同前后缀的后一个字符),返回执行第1步;
循环结束时,查看j值是否等于P的长度,如果等于则匹配成功,否则主串中不包含匹配串。
计算最长相同前后缀:
新建一个数组a,数组长度为匹配串P长度。数组的每一位a[i],表示由P[0]~P[i]表示的字符串,最长相同前后缀的位数;
a[0]初始化为0,令i为1,j为0,对于a[i](0<i<len)有两种情况:
1、如果P[j] == P[i],那么a[i] = a[i - 1] + 1;
接着j++,i++重新执行第一步;
2、当P[j] != P[i],如果j此时为0,表示由P[0]~P[i]组成的字符串没有相同的前缀和后缀,所以a[i]=0,i++继续进行第一步;
3、当P[j] != P[i],并且j不为0,表示可能包含相同前缀和后缀,则令j = a[j - 1],继续执行第一步;
直到计算出所有a[i]的值。
AC代码见:
1 class Solution { 2 public: 3 int strStr(char *haystack, char *needle) { 4 int num = strlen(needle); 5 int *next = new int[num]; 6 getNext(needle, next); 7 8 int i = 0; 9 int j = 0; 10 while (haystack[i] != '\0' && needle[j] != '\0') { 11 if (haystack[i] == needle[j]) { 12 ++i; 13 ++j; 14 } else if (j == 0) { 15 ++i; 16 } else { 17 j = next[j - 1]; 18 } 19 } 20 21 free(next); 22 if (needle[j] != '\0') 23 return -1; 24 else 25 return i - j; 26 } 27 28 void getNext(char *needle, int *next) { 29 int i = 1; 30 int j = 0; 31 next[0] = 0; 32 while (needle[i] != '\0') { 33 if (needle[i] == needle[j]) { 34 next[i] = j + 1; 35 ++i; 36 ++j; 37 } else if (j == 0) { 38 next[i] = 0; 39 ++i; 40 } else { 41 j = next[j - 1]; 42 } 43 } 44 } 45 };
代码优化:
实际编写中,为了避免判定j是否为0,简化操作。可以设定next数组,取代a数组。next的含义是,当kmp算法需要寻找子串下一个比较的位置时,直接从next数组中取值;
其中next[0] = -1作为哨兵位,next[i] = a[i - 1],即将a数组整体后移一位保存在next数组中。
AC代码如下:
1 class Solution { 2 public: 3 int strStr(char *haystack, char *needle) { 4 int num = strlen(needle); 5 int *next = new int[num]; 6 getNext(needle, next); 7 8 int i = 0; 9 int j = 0; 10 while (haystack[i] != '\0' && j < num) { 11 if (j == -1 || haystack[i] == needle[j]) { 12 ++i; 13 ++j; 14 } else { 15 j = next[j]; 16 } 17 } 18 19 free(next); 20 if (needle[j] != '\0') 21 return -1; 22 else 23 return i - j; 24 } 25 26 void getNext(char *needle, int *next) { 27 int i = 0; 28 int j = -1; 29 int strl = strlen(needle); 30 next[0] = -1; 31 while (i < strl - 1) { 32 if (j == -1 || needle[i] == needle[j]) { 33 next[++i] = ++j; 34 } else { 35 j = next[j]; 36 } 37 } 38 } 39 };