Substring with Concatenation of All Words

class Solution
{
public:
	vi findSubstring(string s,vector<string>& L)
	{
		if(s.empty()||L.empty())
			return vi();
		int len_word=L[0].length();
		set<int> retS;
		for(int i=0;i<len_word;i++)
		{
			string t=string(&s[0+i],&s[0]+s.length());
			_findSubstring(t,L,retS,i);
		}
		vi ret(retS.begin(),retS.end());
		return ret;
	}
	void _findSubstring(string s,vector<string>& L,set<int>& ret,int off)
	{
		int len_word=L[0].length();
		int sz=L.size();
		//assert(s.length()%len_word==0);
		int word_num=s.length()/len_word;
		if(word_num==0)
			return ;

		int i,j;

		vector<string> words;
		vector<int> wordsTime;
		words.push_back(L[0]);
		wordsTime.push_back(1);
		for(i=1;i<sz;i++)
		{
			for(j=0;j<i;j++)
			{
				if(L[i].compare(L[j])==0)
				{
					wordsTime[j]++;
					break;
				}
			}
			if(j==i)
			{
				words.push_back(L[i]);
				wordsTime.push_back(1);
			}
		}
		int wsz=words.size();

		vi indexs;
		indexs.reserve(word_num);
		for(i=0;i<word_num;i++)
		{
			string t=string(&s[len_word*i],&s[len_word*i]+len_word);
			int idx=-1;
			for(j=0;j<wsz;j++)
			{
				if(words[j].compare(t)==0)
				{
					idx=j;
					break;
				}
			}
			indexs.push_back(idx);
		}

		vi emerge(sz,0);
		int exist=0;
		int left=0;
		for(i=0;i<word_num;i++)
		{
			if (indexs[i]==-1)
			{
				for(j=left;j<i;j++)
				{
					emerge[indexs[j]]--;
					exist-=1;
				}
				left=i+1;
			}
			else if (emerge[indexs[i]]==wordsTime[indexs[i]])
			{
				emerge[indexs[i]]=-1;
				for(j=left;emerge[indexs[j]]!=-1;j++)
				{
					emerge[indexs[j]]--;
					exist--;
				}
				emerge[indexs[i]]=wordsTime[indexs[i]];
			
				left=j+1;
			}
			else
			{
				emerge[indexs[i]]++;
				exist++;
				if (exist==sz)
				{
					ret.insert(len_word*left+off);
					emerge[indexs[left]]--;
					exist--;
					left++;
				}
			}
		}
		
	}
};


题目如下:

You are given a string, S, and a list of words, L, that are all of the same length. Find all starting indices of substring(s) in S that is a concatenation of each word in L exactly once and without any intervening characters.

For example, given:
S: "barfoothefoobarman"
L: ["foo", "bar"]

You should return the indices: [0,9].
(order does not matter).

 

在编程之美上有一个题与此类似,此题不同在于

1.L中每个单词只能出现一次

2.单词间必须是连续的

注意L中的单词可以有重复的,如L[ "a","b","a"],所以统计每个单词应当出现的次数的时候,要考虑重复;

另外很恶心的是待检查的是个字符串而不是一个数组,我采用的方法是首先在s[0]开头的子串中检查;然后是s[1]。。。可知这样的效率实在很差,尤其是L中单词的长度很长的时候。

如果您有更好的方法,希望能告知我~

 

解题思想:

1.首先为L中数组建立希望的重复次数数组words_time,同时去除掉重复的单词words,这部分的复杂度是O( len(L[0]) * len( L[0]) );

2.将待检查的子串S按L[0]的长度分成K ( K=len(S) / len(L[0]) )个等长单词,同时建立S中单词在words中的下标,这部分的复杂度是 O( K * len(L[0] ) );

3.枚举S'  ( S ' 是原S去掉开头的子串) 中的每一个单词i,同时维护当前已包含单词的范围最左单词left,检查单词i 的出现情况:

      3.1 如果该单词根本不属于words,按题意已经得到的这个范围的所有单词都无效;

      3.2 如果该单词已经出现到需要的次数,应当擦去范围中该单词第一次出现及之前出现的所有单词;

      3.3 如果该单词还可以出现,检查是否满足输出条件;

      因为预处理建立的indexs数组使得第三步擦去每个无效单词可在常数时间完成,所以这部分的复杂度是 O ( K ) ;

 

如前面提到,必须对 S[0]、S[1].......S[ len(L[0]) -1]  依次调用上述过程,所以总的复杂度是 O(len(L[0]) * ( len( L[0] )^2 + K* len(L[0]) + K ) ;

 

代码较乱较丑陋,有时间再改吧。

 

 

你可能感兴趣的:(Substring with Concatenation of All Words)