答案 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;
对于次二次算法,请参阅 这可能是גלעדברקן想要的代码,而不是遵循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