给定两个离散随机变量,它们(任意)概率质量函数a
和b
以及自然数N
,使得两个变量都具有域{{1} (因此函数可以表示为数组),函数的相应随机变量具有给定总和(即[0..N]
)的概率可以在O(N)时间内通过将数组视为向量来计算并使用他们的点积,虽然其中一个输入被反转,两个输入都被重新切片以便对齐它们并消除边界误差;因此,P(A+B==target)
的每个职位i
都与a
的职位j
匹配,以便b
。这样的算法看起来像这样:
i+j==target
给定相同的信息,可以将变量的和作为其自己的离散随机变量,尽管其概率质量函数未知。评估该概率质量函数的整体(从而产生与其对应的阵列)可以通过执行N个点积来在O(N 2)时间内完成,每个乘积的操作数被不同地移位;即:
-- same runtime as dotProduct and sum; other components are O(1)
P :: Vector Int -> Vector Int -> Int -> Ratio Int
P a b target | length a /= length b = undefined
| 0 <= target && target <= 2 * length a
= (dotProduct (shift target a) (reverse (shift target b)))
%
(sum a * sum b) -- O(length a)
-- == sum $ map (\x -> (a!x)*(b!(target-x))) [0..length a]
| otherwise = 0
where
-- O(1)
shift t v = slice start' len' v
where start = t - length v - 1
len = length v - abs start
-- unlike `drop ... $ take ... v`,
-- slice does not simply `id` when given out-of-bounds indices
start' = min (V.length v) (max 0 start)
len' = min (V.length v) (max 0 len)
-- usual linear-algebra definition
-- O(length a); length inequality already guarded-away by caller
dotProduct a b = sum $ zipWith (*) a b
然而,我被告知,产生这种概率质量函数值的表实际上可以在O(N * log(N))时间内完成。据我所知,所有涉及的点积的乘法中没有两个共享相同的有序索引对,我不认为我可以,例如,以任何有用的方式组合两个点子副产品来形成一个pm :: Vector Int -> Vector Int -> Vector (Ratio Int)
pm a b = map (P a b) $ generate (2 * length a + 1) id
类型的递归;因此,我很好奇如何以及为什么这样的运行时是可能的。