[英]Java Optimizing arithmetic and Assignment Operators for large input
我有一段代码必须在时钟速度方面非常快地运行。 该算法已经在O(N)中。 它需要2秒,需要1秒。 对于大多数A.length输入,大约100,000,它需要0.3秒,除非特定的代码行被调用了极端的次数。 (对于深奥的编程挑战)
它使用一种计算公式,即1,2,.N-> 1,3,4,10,15 ..可以由n *(n + 1)/ 2个I循环表示,通过该方程式有数百个成千上万次。 我无法访问输入,也无法显示它。 我能够获得的唯一信息是运行时间。 特别是等式是:
s+=(n+c)-((n*(n+1))/2);
s和c的值可以是0到10亿
n的范围可以从0到100,000
根据时钟速度编写此语句的最有效方法是什么? 我听说除法需要更多的时间然后乘法,但除此之外,我无法确定在一行或多个赋值行中写这个是否更有效。 除以乘法再乘以然后除以? 创建自定义整数类型也有很大帮助吗?
根据请求编辑,带有小输入案例的完整代码(对不起,如果它很难看,我只是继续剥离它):
public static void main(String[] args) {
int A[]={3,4,8,5,1,4,6,8,7,2,2,4};//output 44
int K=6;
//long start = System.currentTimeMillis();;
//for(int i=0;i<100000;i++){
System.out.println(mezmeriz4r(A,K));
//}
//long end = System.currentTimeMillis();;
// System.out.println((end - start) + " ms");
}
public static int mezmeriz4r(int[]A,int K){
int s=0;
int ml=s;
int mxl=s;
int sz=1;
int t=s;
int c=sz;
int lol=50000;
int end=A.length;
for(int i=sz;i<end;i++){
if(A[i]>A[mxl]){
mxl=i;
}else if(A[i]<A[ml]){
ml=i;
}
if(Math.abs(A[ml]-A[mxl])<=K){
sz++;
if(sz>=lol)return 1000000000;
if(sz>1){
c+=sz;
}
}else{
if(A[ml]!=A[i]){
t=i-ml;
s+=(t+c)-((t*(t+1))/(short)2);
i=ml;
ml++;
mxl=ml;
}else{
t=i-mxl;
s+=(t+c)-((t*(t+1))/(short)2);
i=mxl;
mxl++;
ml=mxl;
}
c=1;
sz=0;
}
}
if(s>1000000000)return 1000000000;
return s+c;
}
从挑战返回:
检测到的时间复杂度:
上)
测试时间结果
示例测试0.290秒。 好
单个单个元素0.290 s。 好
双重两个元素0.290 s。 好
小功能小功能测试0.280秒。 好
small_random小随机序列长度= ~100 0.300 s。 好
small_random2小随机序列长度=〜100 0.300 s。 好
medium_random混沌介质序列长度=〜3,000 0.290 s。 好
large_range大范围测试,长度= ~100,000 2.200 s。 超时错误运行时间:> 2.20秒,时间限制:1.02秒。
large_random随机大序列长度= ~100,000 0.310 s。 好
large_answer测试,答案很大,为0.320秒。 好
large_extreme所有最大值= ~100,000 0.340 s。 好
有了一点代数,您可以简单地将表达式(n+c)-((n*(n+1))/2)
到c-((n*(n-1))/2)
来删除加法运算。 然后,您可以将除法值替换为2
,向右移位1
,这比除法更快。 尝试更换
s+=(n+c)-((n*(n+1))/2);
同
s+=c-((n*(n-1))>>1);
我会尝试以下内容并在每次更改后对代码进行分析,以检查速度是否有任何增益。
更换:
if(Math.abs(A[ml]-A[mxl])<=K)
通过
int diff = A[ml]-A[mxl];
if(diff<=K && diff>=-K)
更换
/2
通过
>>1
更换
ml++;
mxl=ml;
通过
mxl=++ml;
也许避免对同一元素的数组访问(java的内部边界检查可能需要一些时间)
所以staore至少A[i]
在局部变量中。
在for循环中删除System.out.println():)您会惊讶于计算速度有多快
嵌套分配,即代替
t=i-ml;
s+=(t+c)-((t*(t+1))/(short)2);
i=ml;
ml++;
mxl=ml;
就像是
s+=((t=i-ml)+c);
s-=((t*(t+1))/(short)2);
i=ml;
mxl=++ml;
有时发生在OpenJDK源代码中。 它主要导致用*dup
s替换*load
字节码指令。 根据我的实验,它确实提供了非常小的加速,但它是超强的,我不建议手动编写这样的代码。
我无权验证所有输入。 和时间范围。 但这肯定是O(N)。 并有所改善。 跑,让我知道你的反馈。如有必要,我会提供详细信息
public static int solution(int[]A,int K){
int minIndex=0;
int maxIndex=0;
int end=A.length;
int slize = end;
int startIndex = 0;
int diff = 0;
int minMaxIndexDiff = 0;
for(int currIndex=1;currIndex<end;currIndex++){
if(A[currIndex]>A[maxIndex]){
maxIndex=currIndex;
}else if(A[currIndex]<A[minIndex]){
minIndex=currIndex;
}
if( (A[maxIndex]-A[minIndex]) >K){
minMaxIndexDiff= currIndex- startIndex;
if (minMaxIndexDiff > 1){
slize+= ((minMaxIndexDiff*(minMaxIndexDiff-1)) >> 1);
if (diff > 0 ) {
slize = slize + (diff * minMaxIndexDiff);
}
}
if (minIndex == currIndex){
diff = currIndex - (maxIndex + 1);
}else{
diff = currIndex - (minIndex + 1);
}
if (slize > 1000000000) {
return 1000000000;
}
minIndex = currIndex;
maxIndex = currIndex;
startIndex = currIndex;
}
}
if ( (startIndex +1) == end){
return slize;
}
if (slize > 1000000000) {
return 1000000000;
}
minMaxIndexDiff= end- startIndex;
if (minMaxIndexDiff > 1){
slize+= ((minMaxIndexDiff*(minMaxIndexDiff-1)) >> 1);
if (diff > 0 ) {
slize = slize + (diff * minMaxIndexDiff);
}
}
return slize;
}
if(Math.abs(A[ml]-A[mxl])<=
通过更快的自我计算的abs版本(内联,而不是方法调用),我会尝试消除这一行!
转换为(短)没有帮助,但尝试右移位运算符X >> 1而不是x / 2
删除System.out.println()可以加速1000倍。但是要小心,否则你的整个算法可以被VM删除因为你不使用它。 旧代码:
for(int i=0;i<100000;i++){
System.out.println(mezmeriz4r(A,K));
}
新代码:
int dummy = 0;
for(int i=0;i<100000;i++){
dummy = mezmeriz4r(A,K);
}
//Use dummy otherwise optimisation can remove mezmeriz4r
System.out.print("finished: " + dummy);
我将首先创建一个C版本,然后看看“直接访问金属”可以执行多快。 您可能正在尝试优化已经优化到极限的计算。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.