如何查找数组中的反转次数?

时间:2010-12-29 08:32:53

标签: arrays algorithm sorting

  

可能重复:
  Counting inversions in an array

这是phone interview question:“查找数组中的反转次数”。我猜他们的意思是O(N log N)解决方案。我认为它不能比O(N log N)更好,因为这是排序的复杂性。

similar question的答案可归纳如下:

  1. 计算元素移动距离的一半以对数组进行排序:复制数组并对副本进行排序。对于原始数组a[i]的每个元素,在排序副本(二进制搜索)中找到它的位置j,并将距离abs(i - j)/2的一半加起来。
  2. 修改merge sort:修改merge以计算两个已排序数组之间的反转,并使用修改后的merge sort运行常规merge

    有意义吗?还有其他(可能更简单)的解决方案吗?电话采访难道不是很难吗?

2 个答案:

答案 0 :(得分:20)

它实际上是分治算法的应用,如果您熟悉它,您可以快速提出解决方案。

以[1 3 8 5 7 2 4 6]为例,假设我们已将数组排序为[1 3 5 8]和[2 4 6 7],现在我们需要将这两个数组合并得到总反转次数。

由于我们已经在每个子数组中有多个反转,我们只需要找出数组合并引起的反转次数。每次插入一个元素,例如插入[1#3 5 8]时,您就可以知道第一个数组和元素2之间存在多少个反转(本例中为3对)。然后你可以将它们相加以获得合并引起的反转次数。

答案 1 :(得分:4)

如果数组仅包含小数字(例如,如果它是字符数组),您也可以使用类似计数的方法:

inversions = 0
let count = array of size array.Length
for i = 0 to array.Length - 1 do
    for j = array[i] + 1 to maxArrayValue do
        inversions = inversions + count[j]

    count[array[i]] = count[array[i]] + 1

基本上,记住每个元素出现的次数。然后在每个步骤ii元素生成的反转次数等于i之前大于i的所有元素的总和,可以使用您保留的计数轻松计算。

这将是O(n*eps),其中eps是数组中元素的域。

在我看来,这绝对更简单。至于效率,只有eps显然很小才有用。如果是,那么它应该比其他方法更快,因为没有递归。