[英]Multiple of 3 or 5 in ascending order
我想以最快的方式获得给定数字以下3或5的所有数字。 所以我做了下面的代码:
double limit = number / 5;
for (var i = 0; i <= number / 3; i++)
{
list.Add(i * 3);
if (i <= limit && ((i * 5) % 3 != 0))
{
list.Add(i * 5);
}
}
但是结果列表不会按升序排序。 如果number = 11
,则列表包含
0、3、5、6、10、9
代替
0、3、5、6、9、10
要获得排序列表,我可以使用一个简单的迭代,例如:
for (var i = 0; i <= number; i++)
{
if (i % 3 == 0 || i % 5 == 0)
{
list.Add(i);
}
}
但是练习的主要目的是纠正最快的算法。
我在第一种算法中缺少什么还是应该保留第二种算法?
这是我的实现,尽管按照BigO表示法可能不是最快的。
static void Main(string[] args)
{
int number = 35;
List<int> list = new List<int>();
int count3 = 0;
int count5 = 0;
int step3 = 3;
int step5 = 5;
while (count3 < number || count5<number )
{
if ((count3 + step3) <= (count5 + step5))
{
count3 += step3;
if (count3 <= number)
{
list.Add(count3);
}
}
else
{
count5 += step5;
if (count5 <= number)
{
list.Add(count5);
}
}
}
foreach (var l in list)
{
Console.WriteLine(l.ToString());
}
Console.ReadLine();
}
对于3和5,每15(3 * 5 = 15)就有一个循环依赖关系,这就是为什么我们只能做这样的事情:
static void Main()
{
int[] deltas= { 3,2,1,3,1,2,3 };
int number = 30;
List<int> result = new List<int>();
int j = 1;
for(int i = deltas[0]; i<=number; i+=deltas[j++%deltas.Length])
{
result.Add(i);
}
foreach(int i in result)
Console.Write(i+", ");
}
更新:
为了找到圆点,我们需要计算最小公倍数。 现在,要找到到此为止的所有增量,我们只需要以较不理想的方式解决原始问题,并将彼此相减即可。
更通用的版本:
static void Main()
{
foreach(int i in multi(30, new []{2,3,4,5,7} ))
Console.Write(i+", ");
}
static List<int> multi(int max, int[] divs)
{
int[] deltas = calcDeltas(divs);
List<int> result = new List<int>();
int j = 1;
for(int i = deltas[0]; i<=max; i+=deltas[j++%deltas.Length])
{
result.Add(i);
}
return result;
}
static int[] calcDeltas(int[] divs)
{
long max = 1;
foreach(int div in divs)
max = lcm(max,div);
List<long> ret = new List<long>();
foreach(int div in divs)
{
for(int i=div; i<=max; i+=div)
{
int idx = ret.BinarySearch(i);
if (idx < 0)
{
ret.Insert(~idx, i);
}
}
}
for(int i=ret.Count-1; i>0; i--)
ret[i]-=ret[i-1];
return ret.ConvertAll(x => (int)x).ToArray();
}
static long gcf(long a, long b)
{
while (b != 0)
{
long temp = b;
b = a % b;
a = temp;
}
return a;
}
static long lcm(long a, long b)
{
return (a / gcf(a, b)) * b;
}
更新2:
我对提供的解决方案(没有Eric的解决方案)进行了一些测试。 我修改了一些函数以给出完全相同的结果(更多描述)。 在i7-3770K@3.5GH上测试。
用户名-说明
时间1-平均时间,循环= 100,数字= 10000000
时间2-总时间,循环= 100000,数字= 10000
时间3-总时间,循环= 1000000,数字= 100
CPU使用率-百分比
Mrinal Kamboj-建议使用OrderBy保留正确的订单
434ms,85447ms,348600ms, 70%
Mrinal Kamboj-建议使用OrderBy来保留正确的订单,而不使用ToList()来实现已完成的查询ForAll(x => {})
136ms,51266ms,273409ms, 80%
Mrinal Kamboj-不带AsParallel
154ms,14559ms,1985ms,13%
MHD-第二个解决方案
69ms,5791ms,879ms,13%
ThomW-添加条件以防止重复
34ms,2398ms,521ms,13%
Logman-带有3,5的预先计算的增量作为原始答案
43ms,3498ms,654ms,13%
Logman-通用解决方案
47ms,3529ms,1270ms,13%
Logman + HABO-带有3,5的预先计算的增量
37ms,2655ms,501ms,13%
Logman + HABO-通用解决方案
37ms,2701ms,1149ms,13%
HABO-展开的解决方案(请参阅评论)
32ms,2072ms,464ms,13%
我想以最快的方式获得低于给定数字3或5的所有数字。
轻松完成。
private static readonly int [][] lookup = {
{}, // 0
{0}, // 1
{0}, // 2
{0}, // 3
{0, 3}, // 4
{0, 3}, // 5
{0, 3, 5}, // 6
{0, 3, 5, 6}, // 7
{0, 3, 5, 6}, // 8
{0, 3, 5, 6}, // 9
{0, 3, 5, 6, 9}, // 10
... and so on; fill out the table as far as you like
};
现在您的算法是:
static int[] Blah(int x) { return lookup[x]; }
最快的算法几乎总是预先计算的查找表 。 提前解决问题并保存结果; 您的程序然后只查找预先计算的结果。 它通常不会比这更快。 怎么可能
现在很明显,您实际上不是在寻找最快的算法吗? 您实际上在寻找什么算法?
查看结果,值似乎每14个项目包含一个重复模式,这可能是找到最佳算法的关键(缺少扩展的查找表)
总是可以进行更多优化(例如,预先计算预期的大小),但是以下代码可以达到预期的结果,并且应能表现良好:
var list=new List<int>();
int[] seq = {0,3,5,6,9,10,12,15,18,20,21,24,25,27};
for(int i = 0;;){
int val = seq[i % 14] + (i++/14) * 30;
if(val > number)break;
list.Add(val);
}
(附带说明:通常很难衡量的因素是if
是由分支预测引起的,因此,在进行这些难题时,尽可能减少难题总是一个好主意)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.