这是phone interview question:“查找数组中的反转次数”。我猜他们的意思是O(N log N)解决方案。我认为它不能比O(N log N)更好,因为这是排序的复杂性。
similar question的答案可归纳如下:
a[i]
的每个元素,在排序副本(二进制搜索)中找到它的位置j
,并将距离abs(i - j)/2
的一半加起来。修改merge sort
:修改merge
以计算两个已排序数组之间的反转,并使用修改后的merge sort
运行常规merge
。
有意义吗?还有其他(可能更简单)的解决方案吗?电话采访难道不是很难吗?
答案 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
基本上,记住每个元素出现的次数。然后在每个步骤i
,i
元素生成的反转次数等于i
之前大于i
的所有元素的总和,可以使用您保留的计数轻松计算。
这将是O(n*eps)
,其中eps
是数组中元素的域。
在我看来,这绝对更简单。至于效率,只有eps
显然很小才有用。如果是,那么它应该比其他方法更快,因为没有递归。