这里有两种不同的解决方案,用于查找“乘积小于K的子数组的数量”,一种具有运行时O(n),另一种具有O(n ^ 2)。但是,O(n ^ 2)的执行速度比线性运行时复杂度(1s对4s)的执行速度快约4倍。有人可以解释为什么会这样吗?
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");
}
我在示例测试程序中选择的数组大小有300,000,000个元素。
O(n)花了4152ms
O(n ^ 2)耗时1486ms
O(n)花了1505毫秒
O(n ^ 2)用了480ms
O(n)花费了2ms
O(n ^ 2)花费了0ms
答案 0 :(得分:8)
您选择的数字均匀分布在[2,1001]范围内,并且您要对乘积小于500的子数组进行计数。发现大子数组的可能性本质上为0;但是,如果要对这些子数组进行计数,则结果为0。乘积小于500的可能的最长子数组长度为8,只有9个具有该长度的子数组(全为2,八个数组为7个2和3);击中其中之一的可能性很小。一半的数组值已经超过500;在给定的起始点发现甚至两个长度的子数组的概率也不到四分之一。
因此,从理论上讲,您的O(n²)算法在该测试中实际上是线性的。而且您的O(n)算法需要在每个点进行除法,这确实很慢;对于较小的n
,速度比n
慢。
答案 1 :(得分:0)
在第一个中,您正在除(慢),相乘并进行多次求和。
在第二个中,较重的运算是乘法,并且如第一个答案所述,该算法对于您的测试用例实际上是线性的。