给定一个 N 整数数组(正数和负数),找到连续子数组的数量,其总和大于或等于 K(同样,正面或负面的)
我设法制定了一个天真的O(N 2 )解决方案,是否有可能变得更好?
答案 0 :(得分:5)
是的,可以在O(n log n)
时间内完成。
让我们来看看前缀总和。 (L, R]
子阵列的总和为prefixSum[R] - prefixSum[L]
。
这意味着我们可以计算L
和R
的{{1}}和L < R
的数量,这意味着prefixSum[R] - prefixSum[L] >= K
。
让我们从左到右迭代前缀和数组,并维护一个可以有效执行以下操作的数据结构:
为此,我们可以使用平衡的二叉搜索树。
以下是此解决方案的伪代码:
prefixSum[L] <= prefixSum[R] - K
时间复杂度为tree = an empty search tree
result = 0
// This sum corresponds to an empty prefix.
prefixSum = 0
tree.add(prefixSum)
// Iterate over the input array from left to right.
for elem <- array:
prefixSum += elem
// Add the number of subarrays that have this element as the last one
// and their sum is not less than K.
result += tree.getNumberOfLessOrEqual(prefixSum - K)
// Add the current prefix sum the tree.
tree.add(prefixSum)
print result
,因为有O(n log n)
个添加和计算元素数量的操作,并且每个操作都可以在O(n)
中完成。
答案 1 :(得分:0)
这是另一种解决方案,使用Divide and Conquer方法,时间复杂度为O(n lg n)。
前两个步骤就像上面的帖子一样。
创建前缀和,让我们调用prefixSum []数组。
这意味着我们必须计算L&lt; L&lt; R和prefixSum [R] - prefixSum [L]&gt; = K。
现在,让我们创建另一个数组,让我们称它为arr [],其中arr [i] = prefixSum [N-1-i]为i从0到N-1。
我现在的工作是计算i&lt; i的数量。 j和arr [i] - arr [j]&gt; = K。
为此,我们使用Merge Sort(使用D&amp; C方法):
Suppose that we have MergeSort(arr,left,right) :
... mid = (left + right )/2 ...
MergeSort(arr,left,mid);
MergeSort(arr,mid+1,right);
Merge(arr,left,mid,right);
In Merge function, we add this :
(i: index for the left array : left - mid , j: index for the right array: mid+1 - right)
if (arr[i] >= arr[j] ) {
if ( arr[i] >= arr[j] + K )
count = count + ( mid - i + 1 ); /* because arr[] from i to mid
are all greater or equal to arr[i] so if arr[i]>= arr[j] + K then
arr[] from i to mid are all >= arr[j] + K .*/
.....}
else { // arr[i]<arr[j]
if ( arr[i] >= arr[j] + K ) // K can be negative.
count = count + ( mid - i + 1 );
.....}
在数组中计算Inversion的想法是一样的 https://www.cdn.geeksforgeeks.org/counting-inversions/