求包含字符集的最小子串

40.百度研发笔试题
 2)一串首尾相连的珠子(m 个),有N 种颜色(N<=10),
设计一个算法,取出其中一段,要求包含所有N 中颜色,并使长度最短。

并分析时间复杂度与空间复杂度。

题目来源:
微软等公司数据结构+算法面试100 题V0.1 版
http://topic.csdn.net/u/20101126/10/b4f12a00-6280-492f-b785-cb6835a63dc9.html

分析:

等效为有一个长度为m的字符串,有容量为N的字符集{a,b,c...}构成,求包含字符集的最小子串。

使用set来保存已经存在的字符。

顺序移动子串的开始位置,将set清空,移动子串的结束位置,并将字符加入set,直至set中元素个数为N,表明当前子串已经包含完整字符集;

注意首尾相连,子串结束位置移动到最后后要折回。当子串长度大于当前已知最小长度时,就没必要继续向后移动了,可以直接移动子串的开始位置。

string FindMinSet(const string &str,const set<char> &cset)
{
	cout<<str<<endl;
	string res;
	int str_len=str.length();
	int set_size=cset.size();
	if (str_len<set_size)
		return res;
	int minlen=str_len;
	int besti=0,bestj=0;
	for (int i=0;i<str_len;i++)
	{
		set<char> tempset;
		tempset.clear();
		tempset.insert(str[i]);
		for(int j=(i+1)%str_len;j!=((i+minlen)%str_len);j=(j+1)%str_len)
		{
			tempset.insert(str[j]);
			if (tempset.size()==set_size)
			{
				int thislen=j-i;
				if(thislen<0)
					thislen+=str_len;
				if (thislen<minlen)
				{
					minlen=thislen;
					besti=i;
					bestj=j;

				}
				break;
			}
		}
	}

	if (besti<bestj)
	{
		res=str.substr(besti,bestj+1-besti);
	}
	else
	{
		res=str.substr(besti,str_len-besti)+str.substr(0,bestj+1);
	}
	cout<<"len="<<minlen<<"	i="<<besti<<"	j="<<bestj<<endl;
	cout<<res<<endl;
	return res;
}
//测试用例
void FindMinSet( )
{
	char cc[]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n'};
	set<char> cset;
	for(int i=0;i<sizeof(cc)/sizeof(char);i++)
		cset.insert(cc[i]);

	string str;

	srand(time(NULL));
	for(int i=0;i<120;i++)
		str+=cc[rand()%(sizeof(cc)/sizeof(char))];
	FindMinSet(str,cset);


}


你可能感兴趣的:(数据结构,算法,String,面试,百度,null)