本届大赛由微软必应词典冠名,必应词典(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取余数之后的结果。
选择方法二,结果失败了!
方法一:递归过多堆栈溢出(字符串长度不能超过几百)
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace Bing个数{ /// <summary> /// 一、首先去掉字符串首尾的无关字符,使其成为如下格式:b......g /// 二、确定"b"后第一个"i"后"n"的个数计数;再找第二个"i"后"n"的个数计数...直到所有的"i"后"n"都被找完。 /// 三、确定倒数第二个"g"字符(去掉字符串右端的无关字符),递归步骤二...直到第一个有用的"g"被找完 /// 四、确定第二个"b"(去掉字符串左端的无关字符),重复步骤二、三...直到最后一个有用的"b"被找完 /// </summary> class Program { /// <summary> /// b......g间所能组成bing所有方案个数 /// </summary> /// <param name="oldstr"> 原先字符串 </param> /// <param name="newstr"> 操作字符串,通过"i"找到后面"n"的个数 </param> /// <param name="count"> 个数</param> /// <returns></returns> public static void getCount( string oldstr, string newstr, ref int count) { //newstr = "hjsdhifdnnsi"; int indexI = newstr.IndexOf('i' ); if (indexI > 0) { StringBuilder m = new StringBuilder(); StringBuilder n = new StringBuilder(); //m = new StringBuilder(newstr.Substring(indexI)); m = new StringBuilder (newstr).Remove(0, indexI); //此"i"位置后所有"n"的个数 count += ( from c in m.ToString() where c == 'n' select c).Count(); //去掉当前"i" //newstr = newstr.Remove(indexI, 1); n = new StringBuilder (newstr).Remove(indexI, 1); newstr = n.ToString(); m.Clear(); n.Clear(); //递归 getCount(oldstr, newstr, ref count); } else { if (oldstr.IndexOf('i' ) > 0 && oldstr.Length >= 4) { //b...g,找到字符串末端第2个"g"字符递归 oldstr = oldstr.Remove(oldstr.Length - 1, 1).TrimEnd( new char [] { 'i', 'n', 'b' }); newstr = oldstr; getCount(oldstr, newstr, ref count); } } } static void Main(string[] args) { int n = 0, count = 0, totalCount = 0; string[] bing = new [] { "b", "i", "n" , "g" }; StringBuilder bingStringBuilder = new StringBuilder(); Random r = new Random(); for (int i = 0; i < 10000; i++) { n = r.Next(0, 4); bingStringBuilder = bingStringBuilder.Append(bing[n]); } //创建只包含字符‘b’、‘i’、‘n’、‘g’且长度不超过10000的字符串 string bingStr = bingStringBuilder.ToString(); //去掉首尾不能组合成bing的字符即b......g bingStr = bingStr.TrimStart( new char [] { 'i', 'n', 'g' }).TrimEnd( new char [] { 'i', 'n', 'b' }); while ((from c in bingStr where c == 'b' select c).Count() != 0) { //b......g格式下bing个数 getCount(bingStr, bingStr, ref count); totalCount += count; //去掉字符"b" bingStr = bingStr.Remove(0, 1); //b......g,确定下一个"b"字符 bingStr = bingStr.TrimStart( new char [] { 'i', 'n', 'g' }); count = 0; } Console.WriteLine("包含字符‘b’、‘i’、‘n’、‘g’且长度不超过10000的字符串为:" + bingStringBuilder); Console.WriteLine(); Console.WriteLine("组合成单词\"bing\"的个数:" + totalCount); Console.WriteLine(); Console.WriteLine("输出对10^9 + 7取余数之后的结果:" + totalCount % 1000000007 ); Console.ReadLine(); } }}
方法二:当字符串长度为10000时运行超时(整个下来会非常耗时,用Stopwatch测了下差不多要8分钟)改为1000了,对10^9 + 7取余数之后的结果(悲催的写成1000000007 % totalCount了)挑战失败!
using System;using System.Collections;using System.Collections.Generic;//using System.Linq;using System.Text;/// <summary>/// 解题思路:/// 一、创建只包含字符‘b’、‘i’、‘n’、‘g’且长度不超过10000的字符串bingStr,用两个数据集合iList与gList记录下字符"i","g"的所在位置/// 二、遍历iList集合,记录字符"i"前字符"b"的个数;在遍历中嵌套循环gList集合,记录字符"i"与字符"g"间字符"n"的个数。两者相乘累加即为所求/// </summary>public class Test { public static int howmany(string s) { return 0; } //start 提示:自动阅卷起始唯一标识,请勿删除或增加。 public static void Main() { int n = 0; long totalCount = 0; string[] bing = new[] { "b", "i", "n", "g" }; StringBuilder bingStringBuilder = new StringBuilder(); List<int> iList = new List<int>(); List<int> gList = new List<int>(); Random r = new Random(); for (int i = 0; i < 1000; i++) { n = r.Next(0, 4); bingStringBuilder = bingStringBuilder.Append(bing[n]); if (bing[n] == "i") { iList.Add(i); } if (bing[n] == "g") { gList.Add(i); } } //创建只包含字符‘b’、‘i’、‘n’、‘g’且长度不超过10000的字符串 string bingStr = bingStringBuilder.ToString(); foreach (int i in iList) { //当前字符"i"前的字符串子串 string bingStrLeft = bingStr.Substring(0, i); //当前字符"i"前字符"b"的个数 //int bCount = (from c in bingStrLeft where c == 'b' select c).Count(); int bCount = bingStrLeft.Replace("i", "").Replace("n", "").Replace("g", "").Length; if (bCount > 0) { foreach (int g in gList) { //字符"i"在字符"g"前 if (g > i) { //当前字符"i"后字符"g"前(不包含字符"g")的字符串子串 string subBingStr = bingStr.Substring(i, g - i); //此字符串间字符"n"的个数 //int nCount = (from c in subBingStr where c == 'n' select c).Count(); int nCount = subBingStr.Replace("b", "").Replace("i", "").Replace("g", "").Length; //字符"i"字符"g"固定时所能组成"bing"的总个数 totalCount += bCount * nCount; } } } } Console.WriteLine("包含字符‘b’、‘i’、‘n’、‘g’且长度不超过10000(实际长度为1000)的字符串为:" + bingStr); Console.WriteLine(); Console.WriteLine("组合成单词\"bing\"的个数:" + totalCount); Console.WriteLine(); Console.WriteLine("输出对10^9 + 7取余数之后的结果:" + (totalCount == 0 ? 0 : (totalCount % 1000000007))); } //end //提示:自动阅卷结束唯一标识,请勿删除或增加。}