これを解決するための単純な反復動的プログラミング アルゴリズムがあります。1 からn
(順列の長さ) までのすべての i について、その数を取り、 の左側にあるi
要素の数を調べます。昇順で処理するため、表示されない要素はより大きな要素であることがわかります。したがって、それらの要素の数を数えて書き留めます。秘訣は、どの要素がすでに見られているかを追跡するよりも、外部リストを導入することです。P
i
i
i
P
まず、方法でそれを行う方法を見てみましょうO(n^2)
。たとえば、 の場合P=[4, 3, 2, 1]
、アルゴリズムは次のように実行されます。
tree
ゼロに初期化された構造体を作成します。j
j番目の位置にある要素がP
反復アルゴリズムによってすでに見られている場合、位置に「1」を保持します。
1 を取り、 を決定しpos==3
ます。に「1」と書きtree[pos]
ます。どちらが 0 に等しいかを計算します。 にnum_seen=sum(tree[0:3])
書き留めます。この後:pos - num_seen + 1
I[0]
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)
2 番目のトリックは、効率的なデータ構造を使用して、上記の代わりに時間内に表示された要素の数をカウントすることO(n^2)
です。
以下は、フェンウィック ツリーを使用して表示された要素の数を高速にカウントする 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