這幾天閒來無事,看到這個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;