第一个P = [a1, a2, ... , aN]
自然数的排列N
可以用inversions I = [i1, i2, ... , iN]
列表来表示,其中iK
告诉我们有多少个数字在排列K
中K
之前可以找到大于P
的内容。
示例:如果P = [3, 1, 4, 2]
,那么I = [1, 2, 0, 0]
(3被放置1,3和4被放置在2之前,而3和4之前没有更大的数字)。
有一种明显的算法可以将排列从标准形式转换为反转形式,并在O(N^2)
中运行(我们只需遵循定义和计数)。这同样适用于逆转换(稍微不那么直接)。
是否存在时间复杂度较低的算法?
答案 0 :(得分:1)
有一个简单的迭代动态编程算法来解决这个问题:对于从1到n
(置换的长度)的所有i,取i
数并查看{{1}中的多少个元素P
的左边已经看到了。由于我们按递增顺序处理i
,因此我们知道不的元素是大于i
的元素 - 因此我们计算并记下这些元素的数量。诀窍是引入一个外部列表,而不是跟踪i
中已经看到哪些元素。
首先,让我们看看如何以P
的方式进行操作。例如,如果O(n^2)
,则算法将按如下方式执行:
创建一个初始化为零的结构P=[4, 3, 2, 1]
。它拥有" 1"在位置tree
中,如果迭代算法已经看到j
中第j个位置的元素。
取1,确定P
。写" 1"在pos==3
中。计算等于0的tree[pos]
。在num_seen=sum(tree[0:3])
处记下pos - num_seen + 1
。在此之后:I[0]
拿2,写" 1"在树[1]和1 [1]处。 tree = [0, 0, 0, 1], I = [3, 0, 0, 0]
。
拿3,写" 1"在树[2]中,在I [2]下0。 tree = [0, 1, 0, 1], I=[3,1,0,0]
。
选4,写" 1"在树[0]中向下,在I [3]处为0。 tree = [0, 1, 1, 1], I=[3,1,0,0]
。
第二个技巧是使用有效的数据结构来计算tree = [1, 1, 1, 1], I=[3,1,0,0]
时间内看到的元素的数量,而不是上面的O(n log n)
。
这是使用Fenwick树以快速方式计算所见元素数量的Python代码:
O(n^2)
答案 1 :(得分:0)
与此同时,我找到了一个关于伪代码的简单解决方案,它也适用于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])