Java 为什么二次时间算法比线性时间算法执行得更快
这里有两种不同的解决方案用于查找“乘积小于K的子阵列数”,一种是运行时O(n),另一种是O(n^2)。然而,具有O(n^2)的一个比具有线性运行时复杂性(1s vs 4s)的一个执行速度快约4倍。有人能解释一下为什么会这样吗 具有O(n)运行时的解决方案1:Java 为什么二次时间算法比线性时间算法执行得更快,java,algorithm,greedy,Java,Algorithm,Greedy,这里有两种不同的解决方案用于查找“乘积小于K的子阵列数”,一种是运行时O(n),另一种是O(n^2)。然而,具有O(n^2)的一个比具有线性运行时复杂性(1s vs 4s)的一个执行速度快约4倍。有人能解释一下为什么会这样吗 具有O(n)运行时的解决方案1: 静态长计数ProductsLessThank(int[]数字,int k) { if(k=k) prod/=数字[left++]; 计数+=(右-左)+1; } 返回计数; } 具有O(n^2)运行时的解决方案2: 静态长计数Produc
静态长计数ProductsLessThank(int[]数字,int k)
{
if(k=k)
prod/=数字[left++];
计数+=(右-左)+1;
}
返回计数;
}
具有O(n^2)运行时的解决方案2:
静态长计数ProductsLessThank(int[]数字,int k){
长计数=0;
for(int i=0;i=k)
打破
计数++;
}
}
返回计数;
}
主程序示例:
publicstaticvoidmain(字符串[]args){
国际规模=300000000;
int[]数字=新的int[大小];
int-bound=1000;
int k=界/2;
对于(int i=0;i
编辑1:
我在示例测试程序中选择的数组大小有300000000个元素
编辑2:
阵列大小:300000000:
O(n)用了4152ms
O(n^2)用了1486ms
数组大小:100000000:
O(n)用了1505毫秒
O(n^2)耗时480ms
阵列大小:10000:
O(n)用了2ms
O(n^2)需要0毫秒您选择的数字均匀分布在[21001]范围内,并且您正在计算乘积小于500的子阵列。找到大型子阵列的概率基本上为0;乘积小于500的最长可能子阵列的长度为8,并且只有9个该长度的可能子阵列(所有2个,以及7个2和1个3的8个阵列);击中其中一个的概率非常小。一半的数组值已经超过500;在给定的起始点找到甚至两个长度的子阵列的概率小于四分之一
因此,理论上的O(n²)算法与此测试是有效的线性关系。你的O(n)算法需要在每个点上除法,这是非常慢的;小于
n
乘法对于n
的小值,在第一个过程中,您将进行除(慢)、乘和多次求和
在第二个例子中,较重的运算是乘法,正如第一个答案所说,对于您的测试用例,该算法实际上是线性的。数组有多大?数组大小是300000000个元素,int[]类型的解2在这种情况下根本不是二次的,
k
是一个常数,数字至少是2,因此,内部循环只能进行固定次数的迭代,然后才能中断。要正确地进行微基准标记并不是一件小事。您可以使用。首先请查看。很有意思的是,查看上的何时赶上^2上的。如果您为所有i
设置number[i]=2
,并开始增加k
,则在我的计算机上,它们大约在k~1_000_000
处,这说明我的测试输入有偏差。非常感谢。
static long countProductsLessThanK(int[] numbers, int k)
{
if (k <= 1) { return 0; }
int prod = 1;
int count = 0;
for (int right = 0, left = 0; right < numbers.length; right++) {
prod *= numbers[right];
while (prod >= k)
prod /= numbers[left++];
count += (right-left)+1;
}
return count;
}
static long countProductsLessThanK(int[] numbers, int k) {
long count = 0;
for (int i = 0; i < numbers.length; i++) {
int productSoFar = 1;
for (int j = i; j < numbers.length; j++) {
productSoFar *= numbers[j];
if (productSoFar >= k)
break;
count++;
}
}
return count;
}
public static void main(String[] args) {
int size = 300000000;
int[] numbers = new int[size];
int bound = 1000;
int k = bound/2;
for (int i = 0; i < size; i++)
numbers[i] = (new Random().nextInt(bound)+2);
long start = System.currentTimeMillis();
System.out.println(countProductLessThanK(numbers, k));
System.out.println("O(n) took " + ((System.currentTimeMillis() - start)/1000) + "s");
start = System.currentTimeMillis();
System.out.println(countMyWay(numbers, k));
System.out.println("O(n^2) took " + ((System.currentTimeMillis() - start)/1000) + "s");
}