我正在尝试开发一个程序来开发非常快速的素数。素数将在范围内生成(范围<= 10000),结果应在6秒内打印。这是我到目前为止所做的计划。它在我的机器1.73 core 2 duo上运行得很好,并且在3秒内产生结果。但是当我将它提交给在线程序提交验证器时,它会超出时间限制。我甚至删除了try catch block等,因为我认为删除try catch可能会节省很少的资源并为我买几毫秒,但无论我做什么,我总是会超出时间限制。这是我的代码: -
using System;
using System.Collections.Generic;
using System.Linq;
namespace PrimeNumberGenerator
{
class Program
{
static void Main(string[] args)
{
int T = Convert.ToInt32(Console.ReadLine());
List<string> listInput = new List<string>();
for (int i = 0; i < T; i++)
listInput.Add(Console.ReadLine());
for (int i = 0; i < T; i++)
{
string[] str = listInput[i].Split(' ');
int M = Convert.ToInt32(str[0]);
int N = Convert.ToInt32(str[1]);
if ((N - M) <= 100000 && M >= 1 && M <= 1000000000 && N >= 1 && N <= 1000000000)
{
int[] list = Enumerable.Range(M, (N - M + 1)).ToArray();
int k = 2;
while (true)
{
if ((k * k) > N)
break;
for(int j = 0 ; j < list.Count() ;j++)
{
if (list[j] != k && (list[j] % k) == 0 && list[j] != 1 && list[j] != -1)
list[j] = -1;
}
k++;
}
foreach (int item in list)
{
if (item != -1)
Console.WriteLine(item);
}
}
else
Console.WriteLine("Limit exceeded");
}
}
}
}
您必须提供以下输入: -
1
2 30
1不是测试用例,2和30表示应生成2到30之间的所有质数。 如果您只测试一次,可以给它1。如果你能优化这个程序,我将非常感激
提前致谢:)
编辑: -
这是我认为的原始实施,但显然有列表的开销: -
using System;
using System.Collections.Generic;
using System.Linq;
namespace PrimeNumberGenerator
{
class Program
{
static void Main(string[] args)
{
try
{
int T = Convert.ToInt32(Console.ReadLine());
List<string> listInput = new List<string>();
for (int i = 0; i < T; i++)
listInput.Add(Console.ReadLine());
for (int i = 0; i < T; i++)
{
string[] str = listInput[i].Split(' ');
int M = Convert.ToInt32(str[0]);
int N = Convert.ToInt32(str[1]);
List<int> list = null;
if ((N - M) <= 100000 && M >= 1 && M <= 1000000000 && N >= 1 && N <= 1000000000)
{
list = Enumerable.Range(M, (N - M + 1)).ToList();
int k = 2;
while (true)
{
if ((k * k) > N)
break;
List<int> tempList = new List<int>();
foreach (int item in list)
if (item != k && (item % k) == 0 && item != 1)
tempList.Add(item);
list = list.Except(tempList).ToList();
k++;
}
//list.Remove(1);
foreach (int item in list)
Console.WriteLine(item);
Console.WriteLine();
}
else
Console.WriteLine("Limit exceeded");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
}
}
答案 0 :(得分:4)
我只能说,你看起来像循环中的很多循环。可能主要问题只是你的一般算法。
要测试一个数字是否为素数,只需检查它是否可以被2和它的sqrt(向下舍入)之间的任何数字整除。
但是如果你正在检查许多素数,你应该利用这样一个事实:当你检查越来越高的数字时,你只能从素数开始(我会将它们存储在一个简单的List<int>
中)。例如,假设您已达到数字27.您只需要检查它是否可以被2,3或5整除(您已经找到的素数小于sqrt(25),即5),而不是4(因为4可以被2整除 - 如果它可以被4整除,那么它可以被2)整除,而不是高于该值的任何东西(如果它被5以上的任何东西整除,则商将低于5,你就已经检查了它)
这些是一些一般性的概念,应该帮助你优化乍看之下像一个非常低效的算法。
答案 1 :(得分:2)
性能问题有三种解决方案:基准测试,基准测试,基准测试。
使用分析器对代码进行基准测试。对于C#,我个人更喜欢ANTS Performance Profiler,但也有其他选择。
我建议您更新(或发布另一个)具有特定瓶颈的问题。
答案 2 :(得分:1)
您的程序预计会在6秒内输出数字(时间紧迫),因此您应该在6秒内充分利用内存以节省时间。例如,您可以使用多线程或并行编程来更快地生成数字(更多CPU /内存使用)。目前,您正在以常规方式工作,这无法展示C#的优势(您的代码可以直接转换为C / Java /其他几乎没有变化的代码)。你需要用C#方式做,否则你为什么选择C#?这是一个示例(未经过测试,但我认为应该是正确的),这更像是C#方式。
int min = 2;
int max = 10000;
Enumerable.Range(min, max - min + 1)
.AsParallel()
.ForAll(g =>
{
bool prime = true;
for (int i = 2; i <= Math.Sqrt(g); i++)
{
if (g % i == 0)
{
prime = false;
break;
}
}
if (prime) Console.WriteLine(g);
});
编辑:我刚刚测试了代码,在0秒内打印出小于10000的素数,由StopWatch
测量。