计算2个数组之间的反转

时间:2016-03-11 14:17:59

标签: algorithm mergesort divide-and-conquer

我正在寻找一种算法来解决这个问题:

给定2个数组,A和B都是[1..n]的排列,这两个数据之间的反转次数是多少?

这里的反转是当一对元素(i,j)成立时:

if A.indexOf(i) > A.indexOf(j) && B.indexOf(i) < B.indexOf(j)

if A.indexOf(i) < A.indexOf(j) && B.indexOf(i) > B.indexOf(j)

我知道当你可以假设第一个数组已经排序时,有多种方法可以做到这一点,比如在执行MergeSort时计算反转,但我有2个未排序的数组。

示例:

A = [6,3,4,1,2,5] and B = [3,5,2,6,1,4]
No. of inversions = 9
6 has a lower index than 3 in A, but a higher index than 3 in B. This is an inversion.

我希望使用Divide and Conquer方法在O(n log n)时间复杂度中实现这一目标。

2 个答案:

答案 0 :(得分:3)

为了做到这一点,我们可以做一个简单的替换(取自你的例子): 6-> 1,3-> 2,4-> 3,1-> 4,2-> 5,5-> 6。 因此,第一个列表变为[1,2,3,4,5,6],第二个列表变为[2,6,5,1,4,3]。然后,我们可以运行一个简单的O(n log n)算法来计算第二个列表中的反转次数,从而给出答案。

可以使用附加的索引列表在O(n)操作中完成此转换。 ind [i]将是第一个列表中给定数字的索引,因此,如果A [1] = 6,则ind [6] = 1。

构造ind数组的代码:

    var A = new List<int> {6, 3, 4, 1, 2, 5};
    foreach (var num in A) Console.Write(num + " ");
    Console.WriteLine("");

    var indexes = new int[7];
    for (var i = 0; i < 6; ++i)
        indexes[A[i]] = i + 1;

    for (var i = 1; i < 7; ++i) Console.Write(indexes[i] + " ");
    Console.WriteLine("");

然后,给定这个数组(在这个例子[4,5,2,3,6,1]的情况下)我们可以使用resultArray [i] = ind [B [i]]进行替换;

构造替换数组的代码:

    var B = new List<int> {3, 5, 2, 6, 1, 4};

    var resultList = new List<int>();
    for (var i = 0; i < 6; ++i)
        resultList.Add(indexes[B[i]]);

    for(var i = 0; i < 6; ++i)
        Console.Write(resultList[i] + " ");

然后我们可以运行算法来计算最后一个数组中的排列,这将是答案。 (我可以在O(n log n)中给出用于计算排列的代码,但我认为这不是问题所在。)

答案 1 :(得分:0)

这不适合你(O(N ^ 2)时间复杂度):

        int[] A = ...;
        int[] B = ..;

        int count = 0;

        for (int i = 0; i < A.Length-1; i++) {
            for (int j = i+1; j < A.Length; j++) {
                if ((A[i] > A[j] && B[i] < B[j]) || (A[i] < A[j] && B[i] > B[j])) {
                    count++;
                }
            }
        }