一种计算两个数组之间绝对差之和的有效方法?

时间:2018-01-13 08:23:05

标签: algorithm statistics

我有两个数组A和B,可以包含任何正整数或负整数。 我想计算绝对差值的总和,以

给出

$\sum_i^p\sum_j^q|Pi-Qj|

其中p和q分别是Array P和Q的大小。

让我们看一个例子 如果

sti

有没有有效的方法?

2 个答案:

答案 0 :(得分:1)

[2, 4] [4, -3, -4, 4]

已排序:[2, 4] [-4, -3, 4, 4]

qs are negative, p is positive:
2 + 4 + 2 + 3 = sum(4, 3) + 2*2

qs are larger than p:
4 - 2 + 4 - 2 = sum(4, 4) - 2*2

qs are negative, p is positive:
4 + 4 + 4 + 3 = sum(4, 3) + 2*4

qs are equal to p:
4 - 4 + 4 - 4 = 0


qs are smaller than p (not in our example):
5 - 3 + 5 - 2 = -sum(3, 2) + 2*5

qs and p are both negative (not in our example):
  p is larger:
  |-5 - (-7)| + |-5 - (-6)| = 7 - 5 + 6 - 5 = sum(7, 6) - 2*5
  q is larger:
  |-5 - (-3)| + |-5 - (-2)| = 5 - 3 + 5 - 2 = -sum(3, 2) + 2*5

p is negative, qs are positive (not in our example):
|7 - (-5)| + |6 - (-5)| = 7 + 5 + 6 + 5 = sum(7, 6) + 2*5

这里有一些例子,如果数组是递增的,所有这些都可以重用已计算的和,以及乘法。

Q排序并计算前缀和数组,同时记录q转为正的索引(如果有的话)。对于每个p,请在O(log n)O(1)时间内查找上述每个案例的开始和结束部分。使用prefix-sum和p的倍数添加到总计。复杂性:O(n log n)时间,O(n)空间。

答案 1 :(得分:0)

根据符号而不是(“无条件地”)“添加abs()”添加或减去(未修改的)差异可能会或可能不会更有效。
我希望现代编译器,甚至是JIT,能够检测到等价。

! Sum of Absolute Differences between every pair of elements of two arrays;
INTEGER PROCEDURE SAD2(a, b);
    INTEGER ARRAY a, b;
BEGIN
    INTEGER sum, i, j;  ! by the book, declare j locally just like diff;
    sum := 0;
    FOR i := LOWERBOUND(a, 1) STEP 1 UNTIL UPPERBOUND(a, 1) DO
        FOR j := LOWERBOUND(b, 1) STEP 1 UNTIL UPPERBOUND(b, 1) DO BEGIN
            INTEGER diff;
            diff := a(i) - b(j);
            sum := if diff < 0 then sum - diff
                               else sum + diff;
        END;
    SAD2 := sum;
END SAD2;

对于次二次算法,请参阅enter image description here 这可能是גלעדברקן想要的代码,而不是遵循PEP8到点:

''' Given sequences A and B, SAD2 computes the sum of absolute differences
 for every element b from B subtracted from every element a from A.

The usual SAD sums up absolute differences of pairs with like index, only.
'''
from bisect import bisect_right

class state(list):
    ''' Hold state for one sequence: sorted elements & processing state. '''
    def __init__(self, a):
        self.extend(sorted(a))
        self.total = 0
        ''' sum(self[:self.todo]) '''
        self.todo = 0
        ''' next index to do/#elements done '''
    def __str__(self):
        return list.__str__(self) + str(self.todo) + ', ' + str(self.total)

def SAD2(a, b):
    ''' return Sum of Absolute Differences of all pairs (a[x], b[y]). '''
    nPairs = len(a) * len(b)
    if nPairs < 2:
        return abs(a[0] - b[0]) if 0 < nPairs else None
    a = state(a)
    b = state(b)
    sad = 0
    while True:
        key = a[a.todo]
        identical = bisect_right(a, key, a.todo)
        local = 0
        # iterate 'til not lower
        # going to need i: no takewhile(lambda x: x < key, b[todo:])
        i = b.todo
        while i < len(b):
            val = b[i]
            if key <= val:
                break
            local += val
            i += 1
        # update SAD
        # account for elements in a[:a.todo] paired with b[b.todo:i]
        sad += local*a.todo - a.total*(i - b.todo)
        b.todo = i
        n_key = identical - a.todo
        local += b.total
        b.total = local
        # account for elements in a[a.todo:identical] paired with b[:i]
        sad += (key*i - local)*n_key
        if len(b) <= b.todo:
            rest = len(a) - identical
            if 0 < rest:
                sad += sum(a[identical:])*len(b) - b.total*rest
            return sad
        a.todo = identical
        a.total += key * n_key
        a, b = b, a