簡體   English   中英

將置換轉換為反轉表示

[英]Converting permutation to inversion representation

N自然數的置換P = [a1, a2, ... , aN]可以由一系列反演 I = [i1, i2, ... , iN] ,其中iK告訴我們有多少個自然數可以在置換P K之前找到大於K值。

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

有一種顯而易見的算法,可以將排列從標准形式轉換為反轉形式,並以O(N^2) (我們只遵循定義和計數)。 逆轉換也是如此(簡單一點,不那么直接)。

是否有一種算法具有較低的時間復雜度?

有一個簡單的迭代動態編程算法可以解決此問題:對於從1到n (排列長度)的所有i,取數字i然后看一下i剩余的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

同時,我找到了一個關於偽代碼的簡單解決方案,它也適用於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])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM