Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么二次时间算法比线性时间算法执行得更快_Java_Algorithm_Greedy - Fatal编程技术网

Java 为什么二次时间算法比线性时间算法执行得更快

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

这里有两种不同的解决方案用于查找“乘积小于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:
静态长计数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");
}