Leetcode: Substring with Concatenation of All Words

        题目链接:Substring with Concatenation of All Words

        这道题容易想到的是暴力算法,不过一开始就被我否定了,觉得应该不能AC,后来看到网上纯暴力的也能AC,好吧QAQ...

        相比暴力算法,可以下列优化措施:

        (1)L中的字符串可以看作是固定长度的单个“字符”, 这些字符必须是连续出现,且L中的每个字符都要出现一次,不管重复与否。因此我们可以采用移动窗口的思路。左右边界分别记为Wl,Wr,指针Pt移动的单位长度是L中单个字符串的长度。

                i:如果指针所指字符属于L,且该字符重复出现的次数不超过L中重复次数,则Wr = Wr+1;

                ii:如果指针所指字符属于L,但是该字符出现的次数已经达到上限,假设从Wl开始,遍历第一次出现该字符的位置为pos,遍历过程中,遇到其他字符,则在维护字符出

                   现次数的map中,相应字符出现次数减一,更改Wl = pos + 1, Wr = Wr + 1;

                iii:如果指针所指字符不属于L,则Wl = Pt + 1, Wr = Wl

         (2)如上所述,发现每次指针的移动单位是L中单个字符串长度,因此在最开始的Wl位置应该设为:0~~(单位长度-1),这样才不会出现遗漏的情况

         下面贴出AC代码,时间复杂度O(S.length() ):

class Solution{
protected:
	vector vi;
	unordered_map msb;
	int Slen, Llen, Lsize;

protected:
	void Test(string &S, vector &L, int start){
		unordered_map msi;
		int k = 0, l = 0, len = 0;
		string str;
		for (k = start; k < Slen && start <= Slen - Llen*Lsize; k += Llen){
			str = S.substr(k, Llen);
			if (msb.find(str) == msb.end()){
				start = k + Llen;
				len = 0;
				msi.clear();
			}
			else if (msi[str] == msb[str]){
				for (l = start; str != S.substr(l, Llen); l += Llen){
					--msi[S.substr(l, Llen)];
					--len;
				}
				start = l + Llen;
			}
			else{
				++msi[str];
				++len;
			}
			if (len == Lsize){
				vi.push_back(start);
				k = start;
				start += Llen;
				len = 0;
				msi.clear();
			}
		}
	}

public:
	vector findSubstring(string &S, vector &L){
		Slen = S.length(), Llen = L[0].length(), Lsize = L.size();
		for (int i = 0; i < Lsize; ++i)		++msb[L[i]];
		for (int st = 0; st < Llen; ++st)	Test(S, L, st);
		return vi;
	}
};


你可能感兴趣的:(Algorithm)