[英]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]
,則算法將執行如下:
創建一個初始化為零的結構tree
。 如果迭代算法已經看到在P
具有第j個位置的元素,則它將在位置j
保持“ 1”。
取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]
取2,在樹[1]中寫下“ 1”,在I [1]處寫下1。 tree = [0, 1, 0, 1], I=[3,1,0,0]
。
取3,在樹[2]中寫下“ 1”,在I [2]處寫下0。 tree = [0, 1, 1, 1], I=[3,1,0,0]
。
取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.