给一个string S和一个vector<string> L,L中是等长的字符串。寻找S的满足以下条件的子串:该子串是L中的所有string(每个string只能出现一次)的连接,返回字串的位置。如 S: "barfoothefoobarman"
L: ["foo", "bar"],返回结果[0,9]
这道题我最初的想法是两个循环,首先对开始位置beg在[0,Slength-cnt*len)]遍历(其中Slength表示S的长度,cnt表示L中string的个数,len表示每个字符串的长度),之后对一beg开头的长度为cnt*len的子串进行遍历,把遍历过的L中的元素下标相加。如果满足条件,则整数应为n(n-1)/2.如果不等,则该字串不满足条件。
测试错误,主要是没有考虑到L中存在相同元素的可能性。
改进算法,使用map<string,int>,首先保存L中每个元素出现的个数。之后同样的方法遍历S,查找字串,是子串中包含了map中的所有元素请元素出现次数相同。
测试超时
原来的遍历对某些字串遍历了多遍,导致时间复杂度过高。如果L中元素长度为3,则以0为开头的遍历过程中,会找到字串[0,3),[3,6),[7,9)...等,之后再以3为开头的遍历中,会重新遍历[3,6),[6,9)等,所以改进算法。采用类型窗口滑动的方式进行遍历,一个窗口的长度为3,代码如下:
1 class Solution { 2 public: 3 vector<int> findSubstring(string S, vector<string> &L) 4 { 5 vector<int> result; 6 int Slen=S.size(); 7 int cnt=L.size(); 8 int len=L[0].size(); 9 if(Slen<len) 10 { 11 return result; 12 } 13 map<string,int> lmap; 14 map<string,int> tmap; 15 for(size_t i=0;i<cnt;i++) 16 { 17 if(lmap.find(L[i])==lmap.end()) 18 { 19 lmap[L[i]]=1; 20 } 21 else 22 { 23 lmap[L[i]]+=1; 24 } 25 } 26 for(size_t i=0;i<len;i++) 27 { 28 size_t beg=i; 29 for(size_t j=i;j<=(Slen-len);j+=len) 30 { 31 string temp=S.substr(j,len); 32 if(lmap.find(temp)==lmap.end()) 33 { 34 tmap.clear(); 35 beg=j+len; 36 continue; 37 } 38 else if(tmap.find(temp)==tmap.end()) 39 { 40 tmap[temp]=1; 41 } 42 else 43 { 44 tmap[temp]+=1; 45 46 } 47 if(tmap[temp]==lmap[temp]) 48 { 49 if(j-beg==(cnt-1)*len) 50 { 51 result.push_back(beg); 52 tmap[S.substr(beg,len)]--; 53 beg+=len; 54 } 55 } 56 if(tmap[temp]>lmap[temp]) 57 { 58 int k=beg; 59 for(;k<=j;k++) 60 { 61 if(S.substr(k,len)==temp) 62 { 63 break; 64 } 65 } 66 beg=k+len; 67 tmap[temp]--; 68 } 69 } 70 tmap.clear(); 71 } 72 return result; 73 } 74 };