【问题标题】:Computing all infix products for a monoid / semigroup计算幺半群/半群的所有中缀积
【发布时间】:2016-08-01 02:57:14
【问题描述】:

简介:组中缀产品

假设我有一个小组

G = (G, *)

和一个元素列表

A = {0, 1, ..., n} ⊂ ℕ
x : A -> G

如果我们的目标是实现一个功能

f : A × A -> G

这样

f(i, j) = x(i) * x(i+1) * ... * x(j)

(我们不关心如果i > j 会发生什么)

然后我们可以通过预先计算一个前缀表

来做到这一点
m(-1) = 1
m(i) = m(i-1) * x(i)

(右边的1表示G的单位)然后将f实现为

f(i, j) = m(i-1)⁻¹ * m(j)

这是因为

m(i-1) = x(0) * x(1) * ... * x(i-1)
m(j) = x(0) * x(1) * ... * x(i-1) * x(i) * x(i+1) * ... * x(j)

等等

m(i)⁻¹ * m(j) = x(i) * x(i+1) * ... * x(j)

在充分重新关联之后。

我的问题

我们能否挽救这个想法,或者做一些不那么糟糕的事情,如果 G 只是一个幺半群,而不是一个群

对于我的特殊问题,如果G = ([0, 1] ⊂ ℝ, *),我们可以做类似的事情吗,即我们有来自单位行的实数,我们不能除以 0?

【问题讨论】:

  • 我不认为你可以。举个例子:如果 x(i) 之一是 0,那么对于 j>=i,所有 m(j) 都是。这使得所有索引 >=i 的预计算都无用。

标签: algorithm substring dynamic-programming monoids semigroup


【解决方案1】:

是的,如果 G 是 ([0, 1] ⊂ ℝ, *),那么这个想法可以被挽救,从而可以在 O(log n) 时间(或更准确地说,O(log z ) 其中 z 是 A 中 a 的数量,其中 x(a) = 0)。

对于每个 i,计算乘积 m(i) = x(0)*x(1)*...*x(i),忽略任何零(因此这些乘积总是非零)。此外,为所有零元素构建一个索引排序数组 Z。

如果 [i, j] 范围内有零,则 i 到 j 元素的乘积为 0,否则为 m(j) / m(i-1)。

要查找 [i, j] 范围内是否有零,可以在 Z 中进行二进制搜索,以找到 Z 中 >= i 的最小值,并将其与 j 进行比较。这就是额外的 O(log n) 时间成本出现的地方。

一般幺半群解

在 G 是任何幺半群的情况下,可以对 n 个乘积进行预计算,以使任意范围的乘积在 O(log(ji)) 时间内可计算,尽管它比上面更具体的情况有点复杂。

不是预先计算前缀乘积,而是计算所有 i, j 的 m(i, j),其中 j-i+1 = 2^k 对于某些 k>=0,并且 2^k 除 i 和 j。事实上,对于 k=0,我们不需要计算任何东西,因为 m(i, i+1) 的值只是 x(i)。

所以我们需要计算 n/2 + n/4 + n/8 + ... 总产品,最多 n-1 个。

可以从这些构建块(和原始数组的元素)的 O(log_2(j-i+1)) 处构造任意区间 [i, j]:选择区间中包含的最大构建块,然后在它的任一侧附加减小大小的块,直到到达 [i, j]。然后将每个构建块的预计算乘积 m(x, y) 相乘。

例如,假设您的数组大小为 10。例如,我假设 monoid 是自然数的加法。

i: 0  1  2  3  4  5  6  7  8  9
x: 1  3  2  4  2  3  0  8  2  1

2: ----  ----  ----  ----  ----
   4     6     5     8     3

4: ----------- ----------
   10          13

8: ----------------------
   23

这里,2、4 和 8 行显示长度为 2、4、8 的对齐间隔的总和(如果数组的长度不是 2 的幂,则忽略剩余的位)。

现在,假设我们要计算 x(1) + x(2) + x(3) + ... + x(8)。

即 x(1) + m(2, 3) + m(4, 7) + x(8) = 3 + 6 + 13 + 2 = 24。

【讨论】:

  • 对于第一个解决方案,您甚至不需要 O(log n) 查找零,如果您存储(同时填充非零前缀数组)在另一个array 到目前为止看到的零的数量:那么,如果直到 j 的零的数量大于直到 i 的零的数量,你知道 f (i, j) = 0.
  • 我可能会使用你的第二个答案,因为事实证明,由于无聊的数字原因,我们应该完全避免进行反转......
  • 效果很好!在稍微清理一下之后,我将添加一个 ~30 行的 Haskell 实现。为了获得最大的通用性,您可能需要对其进行编辑以强调它甚至不需要幺半群,一个半群就足够了。
猜你喜欢
  • 2014-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-05
  • 2021-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多