问题描述
我编写了以下Java代码,用于使用分而治之方法计算在位向量中找到的1:s数量。我假设我们有一个函数IsZero(int []arr,int low,int high)
(可能不切实际)在O(1)中运行(如果 low 和 high 为0。我将介绍一个主要方法,该方法说明如何使用该算法,以及我自己的IsZero实现(不会以O(1)复杂度运行) 。所以,问题是。鉴于IsZero具有O(1)复杂度,该算法的时间复杂度是多少?
Class Algorithm {
static int NumberOfOnes(int v[]) {
return count(v,v.length-1);
}
static boolean IsZero(int arr[],int high){
for(int i = low; i <= high; i++){
if(arr[i] == 1){
return false;
}
}
return true;
}
static int count(int arr[],int high){
if (low == high && arr[low] == 1) {
return 1;
}
if (high - low == 1) {
return arr[low] + arr[high];
}
if(IsZero(arr,low,high)) {
return 0;
}
int mid = (low + high) / 2;
return count(arr,mid) + count(arr,mid + 1,high);
}
public static void main(String args[]) {
int arr[] = {1,1,1};
int k = NumberOfOnes(arr);
System.out.println(k); //Should print 5 as result
}
}
解决方法
复杂度为O(1 + k * log(n))
与分而治之算法一样,您可以通过将其分成两部分并分别解决这两个部分来解决更大的问题。这将为您提供log(n)
个“层”,其中每个后续层的子问题是上一层的两倍。但是,我们可以直接丢弃某些层(如果没有的话),这意味着在任何时候,我们最多要处理k个子问题。对于每个子问题,我们都调用一次IsZero,因此我们最多进行了k次“事物”总共log(n)
次,从而得出O(1+k*log(n))
。请注意,在k = 0的情况下加了1。
但更严格的界限是O(1 + min(n,k * log(n)))
与其他常见的D&C算法(例如MergeSort)不同,实际上每一层都没有线性步长。这意味着在最坏的情况下(不能丢弃任何子问题),您最多在第一层执行1个“操作”,在第二层执行2个“操作”,然后执行4,8,16,依此类推,直到执行n最后一层中的“事物”。此总和等于2n-1
,当然是O(n)
。
因此,O(n)
和O(1+k*log(n))
都是正确的,因此严格限制为O(1 + min(n,k*log(n)))
。
您当然可以在O(n)
中做到这一点并不令人惊讶,因为琐碎的解决方案在O(n)
中,但是我发现它是您算法的一个相当简洁的属性。