|
Posted on
2009-06-01 17:22
eaglet
阅读( 3419)
评论()
编辑
收藏
举报
刚才在园子里看到 周利华关于 "有道难题"的两道题的算法,eaglet 做了一下,第一题比周利华的算法快10倍左右,第二天快100倍左右。
有道难题之eaglet的算法 刚才在园子里看到 周利华关于 "有道难题"的两道题的算法,eaglet 做了一下,第一题比周利华的算法快10倍左右,第二天快100倍左右。由于eaglet不符合参赛条件,所以就在博客园和大家交流交流吧。
原帖链接
第一道算法题(250分) 话说你在走路上班时,经过一片种植萝卜的农田。这块田地的形状是一个矩形的网格。field的第i个元素的第j个字符,表示田地的第i 行第j列的格子里包含的萝卜的数目。我们定义一个格子的特殊程度为它周围所有格子的萝卜个数的和; 它周围的格子包含它上下左右以及对角相邻的格子,最多有8个,在田地的边界上的格子会少一些。如果一个格子周围没有别的格子,则它的特殊程度为0。 请返回田地中特殊程度在A和B之间的所有格子的数目(包含A,B)。 Definition Class: NumberField Method: countSpecialNumbers Parameters: string[], int, int Returns: int Method signature: int countSpecialNumbers(string[] field, int A, int B) (be sure your method is public) Constraints - field 包含1个到50个元素,含1和50。 - field的每个元素包含1个到50个字符,含1和50。 - field的每个元素包含相同的字符数。 - field的每个元素的字符均为’0’到’9’之一。 - A的范围会在0到100之间,含0和100。 - B 的范围会在A到100之间,含A和100。 Examples 0) {"111", "111", "111"} 4 8 Returns: 5 在这块田地里面,位于角落的格子的特殊程度是3,位于中间的格子的特殊程度是8,其他4个格子的特殊程度为5。 1) {"111", "141", "111"} 4 8 Returns: 9 现在所有的9个格子都满足要求。 2) {"2309", "0239", "2314"} 5 7 Returns: 3 3) {"924", "231", "390", "910", "121"} 31 36 Returns: 0 4) {"5"} 3 8 Returns: 0 5) {"1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890"} 3 18 Returns: 26 下面是eaglet 的算法。
class T1
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif) {
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//// <summary>
/// 获取第i,j格的特殊程度
/// </summary>
/// <param name="field"></param>
/// <param name="i"></param>
/// <param name="j"></param>
/// <returns></returns>
/// <author>eaglet</author>
static private int GetSpecialNumbers(string[] field, int width, int i, int j)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
int y = i - 1 >= 0 ? i - 1: 0;
int sum = 0;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
while (y <= i + 1 && y < field.Length)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
int x = j - 1 >= 0 ? j - 1 : 0;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
while (x <= j + 1 && x < width)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
if (x != j || y != i)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
sum += field[y][x] - '0';
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
x++;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
y++;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return sum;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//// <summary>
///
/// </summary>
/// <param name="field"></param>
/// <param name="A"></param>
/// <param name="B"></param>
/// <returns></returns>
/// <author>eaglet</author>
static public int countSpecialNumbers(string[] field, int A, int B)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
//Check paramaters
if (field == null)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return 0;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (field.Length == 0)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return 0;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
int width = field[0].Length;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (width == 0)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return 0;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (A > B)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
throw new ArgumentException("A > B");
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//Begin calculate
int count = 0;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
for (int i = 0; i < field.Length; i++)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
for (int j = 0; j < field[i].Length; j++)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
int number = GetSpecialNumbers(field, width, i, j);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (number >= A && number <= B)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
count++;
}
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
return count;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif) 测试代码 ![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif) Code Stopwatch sw = new Stopwatch(); string[] testField = { "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890", "1234567890"};
//eaglet 的算法 Console.WriteLine("eaglet 的算法"); Console.WriteLine(T1.countSpecialNumbers(new string[] { "111", "111", "111" }, 4, 8)); Console.WriteLine(T1.countSpecialNumbers(new string[] { "111", "141", "111" }, 4, 8)); Console.WriteLine(T1.countSpecialNumbers(new string[] { "2309", "0239", "2314" }, 5, 7)); Console.WriteLine(T1.countSpecialNumbers(new string[] { "924", "231", "390", "910", "121" }, 31, 36)); Console.WriteLine(T1.countSpecialNumbers(new string[] { "5" }, 3, 8)); Console.WriteLine(T1.countSpecialNumbers(testField, 3, 18));
sw.Start(); for (int i = 0; i < 100000; i++) { T1.countSpecialNumbers(testField, 3, 18); }
sw.Stop();
Console.WriteLine("用时" + sw.ElapsedMilliseconds.ToString() + "毫秒");
//周利华的算法 Console.WriteLine("周利华 的算法");
Console.WriteLine(T1z.countSpecialNumbers(new string[] { "111", "111", "111" }, 4, 8)); Console.WriteLine(T1z.countSpecialNumbers(new string[] { "111", "141", "111" }, 4, 8)); Console.WriteLine(T1z.countSpecialNumbers(new string[] { "2309", "0239", "2314" }, 5, 7)); Console.WriteLine(T1z.countSpecialNumbers(new string[] { "924", "231", "390", "910", "121" }, 31, 36)); Console.WriteLine(T1z.countSpecialNumbers(new string[] { "5" }, 3, 8)); Console.WriteLine(T1z.countSpecialNumbers(testField, 3, 18));
sw.Reset(); sw.Start();
for (int i = 0; i < 100000; i++) { T1z.countSpecialNumbers(testField, 3, 18); }
sw.Stop();
Console.WriteLine("用时" + sw.ElapsedMilliseconds.ToString() + "毫秒");
//西狐.Net 的算法 Console.WriteLine("西狐.Net 的算法");
Console.WriteLine(T1s.countSpecialNumbers(new string[] { "111", "111", "111" }, 4, 8)); Console.WriteLine(T1s.countSpecialNumbers(new string[] { "111", "141", "111" }, 4, 8)); Console.WriteLine(T1s.countSpecialNumbers(new string[] { "2309", "0239", "2314" }, 5, 7)); Console.WriteLine(T1s.countSpecialNumbers(new string[] { "924", "231", "390", "910", "121" }, 31, 36)); Console.WriteLine(T1s.countSpecialNumbers(new string[] { "5" }, 3, 8)); Console.WriteLine(T1s.countSpecialNumbers(testField, 3, 18));
sw.Reset(); sw.Start();
for (int i = 0; i < 100000; i++) { T1s.countSpecialNumbers(testField, 3, 18); }
sw.Stop();
Console.WriteLine("用时" + sw.ElapsedMilliseconds.ToString() + "毫秒");
测试结果 //重复执行10000次
eaglet 的算法 5 9 3 0 0 26 用时1439毫秒 //0.1439毫秒每次 周利华 的算法 5 9 3 0 0 26 用时18205毫秒 西狐.Net 的算法 5 9 3 0 0 26 用时31902毫秒
第二道算法题(500分) 题目要求:双倍超立方数是指一个正整数可以正好被拆分为两种不同的a^3+b^3的方式,其中a,b均为整数且0<a<=b。对于任何一个指定的 int n, 返回所有的小于等于n的双倍超立方数的个数。 Definition Class: TwiceSuperCubic Method: count Parameters: int Returns: int Method signature: int count(int n) (be sure your method is public) Constraints - n取值范围为1到1,000,000,000(含) Examples 0) 1 Returns: 0 1) 1729 Returns: 1 1729=1^3+12^3 1729=9^3+10^3 2) 475574 Returns: 27 eaglet 的代码
class T2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif) {
static List<int> _CubeCache = new List<int>();
static Dictionary<int, int> _CubeCountDict = new Dictionary<int, int>();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) /**//// <summary>
///
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
/// <author>eaglet</author>
static public int count(int n)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
if (n < 0)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return 0;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
_CubeCountDict.Clear();
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//b <= n 的 3 次方根
int max_b = (int)Math.Pow((double)n, 1f / 3);
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//构造整数三次方计算缓存
for (int i = _CubeCache.Count; i <= max_b; i++)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
_CubeCache.Add(i * i * i);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
int count = 0;
int a = 1; //正整数
int b = a;
int sumCube;
sumCube = _CubeCache[a] + _CubeCache[b];
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
do
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
//计算 a^3+b^3
while (sumCube <= n)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
int hit;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//看hash表中有没有已经存在的记录
if (_CubeCountDict.TryGetValue(sumCube, out hit))
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
//存在,且只击中了1次,则计数加1
if (hit == 1)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
count++;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//击中超过1次,计数减1
//存在三组或以上组合相等的情况时走到这个分支
if (hit == 2)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
count--;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
//击中数加一
_CubeCountDict[sumCube]++;
}
else
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
_CubeCountDict.Add(sumCube, 1);
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
b++;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (b > max_b)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
break;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
sumCube = _CubeCache[a] + _CubeCache[b];
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
a++;
b = a;
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
if (b > max_b)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
break;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
sumCube = _CubeCache[a] + _CubeCache[b];
}
while (sumCube <= n);
return count;
}
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif) 测试代码 ![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif) Code //eaglet 的算法 Console.WriteLine("eaglet 的算法"); Console.WriteLine(T2.count(1)); Console.WriteLine(T2.count(1729)); Console.WriteLine(T2.count(475574));
sw.Start(); for (int i = 0; i < 1000; i++) { T2.count(475574); }
sw.Stop();
Console.WriteLine("用时" + sw.ElapsedMilliseconds.ToString() + "毫秒");
//周利华的算法 Console.WriteLine("周利华 的算法");
Console.WriteLine(T2z.count(1)); Console.WriteLine(T2z.count(1729)); Console.WriteLine(T2z.count(475574));
sw.Reset(); sw.Start();
for (int i = 0; i < 1000; i++) { T2z.count(475574); }
sw.Stop();
Console.WriteLine("用时" + sw.ElapsedMilliseconds.ToString() + "毫秒");
测试结果 //重复执行1000次 eaglet 的算法 0 1 27 用时262毫秒 //0.262毫秒每次 周利华 的算法 0 1 27 用时21770毫秒
备注: 由于是算法题,eaglet 对一些参数的检查没有做的很完整,另外没有做线程安全设计,这些已经超出了算法考察的范围,希望大家把讨论的重点放在算法上,eaglet 水平有限,相信园子里像老赵这样的高手应该大把大把的,eaglet热切希望能看到比这个跑的更快的算法出现。
|