No.28 Implement strStr()
Implement strStr().
Returns the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.
分析:
很经典的字符串匹配问题,若可以匹配,返回模式串在字符串中首次出现的下标;否则返回-1
最容易想到的就是暴力破解了,但复杂度高,肯定不是首选。
再就是经典的KMP算法,其实,之前看过好多次,但总是理解不了,后来就不了了之,这次看懂了,记录下。
KMP:
对于不懂KMP算法的人来说,先看看http://kb.cnblogs.com/page/176818/,对KMP有整体把握之后, 再看http://v.youku.com/v_show/id_XNzQzMjQ1OTYw.html视频可以很好的理解以下代码:
1 class Solution 2 { 3 public: 4 int strStr(string haystack, string needle) 5 {//字符串搜索匹配:返回needle在haystack中首次出现的下标;若未出现,返回-1 6 return KMP(haystack, needle); 7 } 8 9 //目的:计算部分匹配表,即next数组 10 //输入:pattern模式串,next为next数组 11 void getNext(string pattern, int next[]) 12 { 13 int m = pattern.size(); 14 if(m==0) 15 return; 16 17 next[0] = -1;//表示的是0之前的串的前缀后缀相同的最大位数 18 int index,j; 19 for(int i=1; i<m; i++) 20 {//next[i]其实表示的是,0~i-1这个字符串的最大相同前缀串和后缀串的长度 21 j = i-1; 22 index = next[j]; 23 while(index >=0 && pattern[index] != pattern[j]) 24 index = next[index]; 25 26 if(index<0) 27 next[i] = 0; 28 else//pattern[index] == pattern[j] 29 next[i] = index+1; 30 } 31 } 32 33 //KMP算法 34 //输入:text文本,pattern模式串;输出:成功则返回第一次匹配的位置;失败则返回-1 35 int KMP(string text, string pattern) 36 { 37 int n = text.size(); 38 int m = pattern.size(); 39 if(n==0 && m==0) 40 return 0;//根据题意,返回0!! 41 if(m==0) 42 return 0;//根据题意,返回0!! 43 int *next = new int[m]; 44 getNext(pattern,next); 45 46 int i=0, j = 0; 47 while(i<n) 48 { 49 if(j==-1 || text[i] == pattern[j]) 50 //j==-1说明text[i]开头的字符串不可能和pattern匹配,所以text直接到下一个字符去 51 { 52 i++; 53 j++; 54 } 55 else 56 j = next[j]; 57 if(j == m)//!!!匹配成功 58 return i-j; 59 } 60 61 delete[] next; 62 return -1; 63 } 64 }; 65 int main() 66 { 67 Solution sol; 68 69 cout << sol.strStr("abaabcabaddsacbads","abaabcaba")<<endl; 70 cout << sol.strStr("BBCABCDABABCDABCDABDE","ABCDABD")<<endl; 71 cout << sol.strStr("abcdefs","adg")<<endl; 72 cout << sol.strStr("abcdefd","ebc")<<endl; 73 cout << sol.strStr("","ebc")<<endl; 74 return 0; 75 }
求解next数组的另一种方法:
1 //目的:计算部分匹配表,即next数组 2 //输入:pattern模式串,next为next数组 3 void getNext(string pattern, int next[]) 4 { 5 int m = pattern.size(); 6 if(m==0) 7 return; 8 9 next[0] = -1;//表示的是0之前的串的前缀后缀相同的最大位数 10 11 int i=0,j=-1;//注意j=-1 12 while(i < m-1)//范围控制到m-1 13 { 14 if(j==-1 || pattern[i] == pattern[j]) 15 { 16 i++; 17 j++; 18 next[i] = j; 19 } 20 else 21 j=next[j]; 22 } 23 24 }
暴力法:leetcode超时
1 class Solution 2 { 3 public: 4 int strStr(string haystack, string needle) 5 {//字符串搜索匹配:返回needle在haystack中首次出现的下标;若未出现,返回-1 6 //暴力法 7 int n = haystack.size();//主串大小 8 int m = needle.size();//模式串大小 9 10 if(m == 0) 11 return 0; 12 13 int pn = 0;//指示主串下标 14 int pm = 0;//指示模式串串下标 15 int cur;//指示当前次匹配主串开始的位置,若匹配,则返回 16 while(pn < n) 17 { 18 while(pn<n && haystack[pn] != needle[pm]) 19 pn++; 20 cur = pn;//找到与模式串首位置相同的位置,然后依次匹配 21 pm++; 22 pn++; 23 while(pn<n && pm<m ) 24 { 25 if(haystack[pn] != needle[pm]) 26 break; 27 pn++; 28 pm++; 29 } 30 31 if(pm == m) 32 return cur; 33 else 34 { 35 pn = cur+1; 36 pm = 0; 37 } 38 } 39 return -1; 40 }