【问题标题】:Converting permutation to inversion representation将排列转换为反转表示
【发布时间】:2016-01-06 09:42:33
【问题描述】:

第一个N自然数的排列P = [a1, a2, ... , aN]可以用inversionsI = [i1, i2, ... , iN]的列表来表示,其中iK告诉我们在@之前可以找到多少个大于K的数排列中的987654327@P

示例:如果P = [3, 1, 4, 2],则I = [1, 2, 0, 0](3 放在 1 之前,3 和 4 放在 2 之前,而 3 和 4 前面没有更大的数字)。

有一个明显的算法可以将排列从标准形式转换为反转形式并在O(N^2) 中运行(我们只需按照定义和计数)。逆向转换也是如此(稍微不那么直接)。

有没有时间复杂度更低的算法?

【问题讨论】:

  • 我认为可以使用 Fenwick 树或类似的数据结构。

标签: algorithm time-complexity permutation inversion


【解决方案1】:

有一个简单的迭代动态规划算法来解决这个问题:对于从 1 到 n(排列长度)的所有 i,取数字 i 并查看 @987654324 左侧的 P 中有多少元素@已经看过了。由于我们按递增顺序处理i,我们知道 看到的元素是大于i 的元素——因此我们计算并记下这些元素的数量。诀窍是引入一个外部列表,而不是跟踪 P 中的哪些元素已经被看到。

首先,让我们看看如何以O(n^2) 的方式进行操作。例如P=[4, 3, 2, 1],那么算法会执行如下:

  1. 创建一个结构tree,初始化为零。如果迭代算法已经看到 P 中第 j 个位置的元素,则它在位置 j 中保持“1”。

  2. 取1,确定pos==3。在tree[pos] 中写下“1”。计算num_seen=sum(tree[0:3]) 等于0。在I[0] 处写下pos - num_seen + 1。在此之后:tree = [0, 0, 0, 1], I = [3, 0, 0, 0]

  3. 取 2,在树 [1] 中写下“1”,在 I[1] 处写下 1。 tree = [0, 1, 0, 1], I=[3,1,0,0]

  4. 取 3,在树 [2] 中写下“1”,在 I[2] 处写下 0。 tree = [0, 1, 1, 1], I=[3,1,0,0]

  5. 取 4,在树 [0] 中写下“1”,在 I[3] 处写下 0。 tree = [1, 1, 1, 1], I=[3,1,0,0]

第二个技巧是使用高效的数据结构来计算O(n log n) 时间内看到的元素的数量,而不是像上面的O(n^2)

这是使用 Fenwick 树快速计算可见元素数量的 Python 代码:

def ft_sum(tree, a, b):
  if a == 0:
      s = 0;
      while  b >= 0:
          s += tree[b];
          b = (b & (b + 1)) - 1
      return s
  return ft_sum(tree, 0, b) - ft_sum(tree, 0, a - 1)

def ft_adjust(tree, k, v):
    while k < len(tree):
        tree[k] += v
        k |= k + 1

def calcI(P):
    n = len(P)
    tree = [0] * n
    I = [0] * n
    positions = [0] * n
    for i in xrange(n):
        positions[P[i]-1] = i
    tree = [0] * n
    for i in xrange(n):
        pos = positions[i]
        ft_adjust(tree, pos, 1)
        num_seen = ft_sum(tree, 0, pos)
        I[i] = pos - num_seen + 1
    return I

【讨论】:

  • 感谢您的努力!我也很欣赏真正的代码(不仅仅是伪代码)。为了完整起见,我将接受您的回答而不是我的回答:)
【解决方案2】:

同时,我找到了一个关于伪代码的简单解决方案,它也适用于O(n log n)

initialize AVL-tree T
initialize array I of length n
for i = 1, 2, ... , n:
    I[P[i]] = T.countGreaterThan(P[i])
    T.add(P[i])

【讨论】:

    猜你喜欢
    • 2010-11-02
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多