如何改进以下程序执行时间。 我已经在"递归"中使用了动态编程。以及" prime"功能。 但没有获得有效的执行时间。
问题:在受害人的房子里有一块4xN的墙。受害者也有无限 在她家里供应4x1和1x4尺寸的砖块。在每一个 配置,墙必须用砖完全覆盖。 Gale Bertram想知道砖块可以在墙上排列的总数,以便每次都能出现新的配置。 设配数= M。
因此,他希望帕特里克计算素数(比如P)直到M(即<= M)。 你需要帮助Patrick正确解决难题。
示例输入 第一行输入将包含一个整数T,后跟T行,每行包含一个 整数N。
示例输出 为每个测试用例打印一行输出。输出应该包含 数字P. 约束 1·; = T&LT; = 20 1·; = N&LT; = 40
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
class Solution{
public static int[] b = new int[217287];
public static void main(String[] args){
Scanner stdin = new Scanner(System.in);
int t = stdin.nextInt();
int[] a = new int[41];
for(int j=0;j<4;j++){
a[j] = 1; //till n<=3, number of possiblities = 1. These will work as base cases.
}
a[4] = 2;
for(int x=0;x<t;x++){
int n = stdin.nextInt();
for(int i=5;i<=n;i++){
a[i] = -1; //initialise all value in the array as -1.
}
if(n<4)
System.out.println("0"); // if n<4, number of possibilities =1. So no prime number before that is 0.
else{
//for n=4, possibilities = 2. This is a base case.
int num1 = recursive(a,n); // storing number of possibilities in num1.
int num2 = prime(num1); //calling to calculate number of prime numbers before or equal to num1.
System.out.println(num2);
}
}
}
public static int recursive(int[] a, int n){
if(a[n]!=-1) // retrieving a[n] value if already calculated.
return a[n];
else{
a[n] = recursive(a,n-1) + recursive(a,n-4); // calling recursively.If we fill with a 4*1 first tile then number
//tiles left is n-1(try visualising).If we fill 1*4 tile first
// we have n-4 tile left.
return a[n];
}
}
public static int prime(int n){
int count = 0;
if(b[n]!=0)
return b[n];
else{
for(int i=2;i<=n;i++){
if(b[i]!=0){
count = b[i];
}
else{
int flag = 0;
for(int j=2;j<=i/2;j++){
if(i%j==0){
flag = 1;
break;
}
}
if(flag==0){
count++;
b[i]=count;
}
}
}
return count;
}
}
}
我得到了以下输入的超时(超过4秒)。 20 35 23 25 38 4 35 19 8 23 35 3 36 12 10 三十 13 18 31 40 37
答案 0 :(得分:1)
你在这里犯了2个重大错误(或者更确切地说是2个效率低下):
a
数组。那些不会改变,只是通过最初分配大小为40的数组重用上次的结果(你也可能想考虑更好的命名约定......)n
对于唯一N
将是唯一的{ {1}} - 再次命名约定)第1部分不太可能增加太多时间,因为计算是微不足道的并且N <= 40
第2部分是搞砸的地方。您可以执行以下操作,而不是只保存b[n]
:从1循环到n
填充b
,其中素数小于或等于i
其中{{1}是索引。这是通过单次素数检查完成的 - 如果i
为素数,则将i
置为b[i-1]
。这意味着您只需检查一个数字是否为每个数字一次(在您当前的实现中,您检查它20次)。您可以在评论中添加一个筛子以进一步提高性能,但上述内容可能会给予足够的加速,在具有给定约束的平庸机器上具有0.1秒的运行时间。
答案 1 :(得分:0)
您可能希望进一步优化int prime(int n)
功能。 (当然,您可以使用'net中的任何有效算法,但:)为了避免再次进行相同的计算,请注意,如果您已经prime(n+m)
,则可以更快地计算prime(n)
。
(我认为你已经在考虑这个方向,因为你已经为已计算的数字使用了一些'缓存'。)
编辑: 见Ordous的回答#2:)
EDIT2:
详细说明这个想法:
问:如果我知道素数c
的数量<= X
,素数<= (X+1)
的数量是多少?
A:c
,如果X+1
不是素数,或c+1
如果X+1
a主要。像这样:
public static int prime2( final int n ) {
int count;
if ( n <= 2 ) {
count = 1;
} else {
count = prime2(n-1);
if ( isPrime(n) ) {
count = count + 1;
}
}
return count;
}
然后添加您的缓存方法来存储任何计算prime2(x)
的结果以供以后使用。