这几天闲来无事,看到这个bing的题,感觉并不是很难,于是就把它写下来。
先看题目:
本届大赛由微软必应词典冠名,必应词典(Bing Dictionary)是微软推出的新一代英语学习引擎,里面收录了很多我们常见的单词,详情请见:http://cn.bing.com/dict/?form=BDVSP4&mkt=zh-CN&setlang=ZH。但现实生活中,我们也经常能看到一些毫无规则的字符串,导致词典无法正常收录,不过,我们是否可以从无规则的字符串中提取出正规的单词呢?
例如有一个字符串"iinbinbing",截取不同位置的字符‘b’、‘i’、‘n’、‘g’组合成单词"bing"。若从1开始计数的话,则‘b’ ‘i’ ‘n’ ‘g’这4个字母出现的位置分别为(4,5,6,10) (4,5,9,10),(4,8,9,10)和(7,8,9,10),故总共可以组合成4个单词”bing“。
咱们的问题是:现给定任意字符串,只包含小写‘b’ ‘i’ ‘n’ ‘g’这4种字母,请问一共能组合成多少个单词bing?
字符串长度不超过10000,由于结果可能比较大,请输出对10^9 + 7取余数之后的结果。
解题思路:
统计一下每一个b后面出现了多少个i,每个i后面出现了多少个n,每个n后面出现了多少个g
然后用递归调用,从b的集合开始循环,统计每个b后面有多少个,依次递归调用,调用i集合,调用n集合,因为g是最后一个,所以就不用调用了
先看第一步,统计
int bindex = -1;
int iindex = -1;
int nindex = -1;
int gindex = -1;
int count = 0;
string t="";
for (int i = 0; i < s.Length; i++)
{
t = s.Substring(i, 1);
if (t == "b")
{
BList.Add(0);
bindex = BList.Count - 1;
}
if (t == "i")
{
IList.Add(0);
iindex = IList.Count - 1;
if (bindex != -1)
{
BList[bindex]++;
}
}
if (t == "n")
{
NList.Add(0);
nindex = NList.Count - 1;
if (iindex != -1)
{
IList[iindex]++;
}
}
if (t == "g")
{
GList.Add(0);
gindex = GList.Count - 1;
if (nindex != -1)
{
NList[nindex]++;
}
}
}
这个统计,并不是累计统计,所以需要一次累计统计:
for(int i = BList.Count - 2; i >= 0; i--)
Blist[i]+=BList[i-1];
分别累计统计后,然后开始递归调用
递归函数如下:
public static int CalCount(List<int> list,int start, int step)
{
long count = 0;
List<int> nextlist=null;
if(step==1)
{
nextlist=IList;
}
if(step==2)
{
nextlist =NList;
}
for (int i = start; i < list.Count; i++)
{
if (step == 3)
{
count += list[i];
count = count % 1000000007;
}
else
{
if (step == 2)
{
if (ICacheList.ContainsKey(i))
{
count += ICacheList[i];
count = count % 1000000007;
}
else
{
if (list[i] > 0)
{
ICacheList.Add(i, CalCount(nextlist, nextlist.Count - list[i], step + 1));
count += ICacheList[i];
count = count % 1000000007;
}
else
{
ICacheList.Add(i, 0);
}
}
}
else
{
count += CalCount(nextlist, nextlist.Count - list[i], step + 1);
count = count % 1000000007;
}
}
}
return (int)(count%1000000007);
}
其中对i集合计算的时候,会重复做无用功,所以,用个缓存集合缓存一下数据
调用就是
表示从b集合开始循环调用,从索引为0的开始统计,表示bing的第一个字符
count = CalCount(BList, 0, 1);
结果还行,10000的长度字符串,本机运行没超过1秒,提交上去后,悲剧了,提示超过3s,吧10000放大到100000,时间好长,看来这种递归方式还是存在问题的。
不过这道题感觉不需要这么多的递归调用啊
再次分析:根据题目,从i分析的时候,可以看出,递归是不需要那么多的,反过来推断,b,n集合也是。
因此改造下对几个集合的统计,那么就不需要递归调用了,统计结果
for (int i = NList.Count - 1; i >= 0; i--)
{
if (i == NList.Count - 1)
{
count = NList[i];
}
else
{
count += NList[i];
NList[i] = NList[i + 1]+count;
count = count % 1000000007;
NList[i] = NList[i] % 1000000007;
}
}
count = 0;
for (int i = IList.Count - 1; i >= 0; i--)
{
if (i == IList.Count - 1)
{
count = IList[i];
if (count != 0)
{
IList[i] = NList[NList.Count - count];
}
else
{
IList[i] = 0;
}
}
else
{
count += IList[i];
if (count != 0)
{
IList[i] = IList[i + 1] + NList[NList.Count - count];
}
else
{
IList[i] = IList[i + 1];
}
count = count % 1000000007;
IList[i] = IList[i] % 1000000007;
}
}
count = 0;
for (int i = BList.Count - 1; i >= 0; i--)
{
if (i == BList.Count - 1)
{
count = BList[i];
if (count != 0)
{
BList[i] = IList[IList.Count - count];
}
else
{
BList[i] = 0;
}
}
else
{
count += BList[i];
if (count != 0)
{
BList[i] = BList[i + 1] + IList[IList.Count - count];
}
else
{
BList[i] = BList[i + 1];
}
count = count % 1000000007;
BList[i] = BList[i] % 1000000007;
}
}
//count = CalCount(BList, 0, 1);
//int result=(int)(count % 1000000007);
int result = 0;
if (BList.Count > 0)
result = BList[0];
return result;