Counting inversions in an array

前端 未结 30 2511
死守一世寂寞
死守一世寂寞 2020-11-22 04:14

I\'m designing an algorithm to do the following: Given array A[1... n], for every i < j, find all inversion pairs such that A[i] > A[j]

30条回答
  •  眼角桃花
    2020-11-22 04:51

    O(n log n) time, O(n) space solution in java.

    A mergesort, with a tweak to preserve the number of inversions performed during the merge step. (for a well explained mergesort take a look at http://www.vogella.com/tutorials/JavaAlgorithmsMergesort/article.html )

    Since mergesort can be made in place, the space complexity may be improved to O(1).

    When using this sort, the inversions happen only in the merge step and only when we have to put an element of the second part before elements from the first half, e.g.

    • 0 5 10 15

    merged with

    • 1 6 22

    we have 3 + 2 + 0 = 5 inversions:

    • 1 with {5, 10, 15}
    • 6 with {10, 15}
    • 22 with {}

    After we have made the 5 inversions, our new merged list is 0, 1, 5, 6, 10, 15, 22

    There is a demo task on Codility called ArrayInversionCount, where you can test your solution.

        public class FindInversions {
    
        public static int solution(int[] input) {
            if (input == null)
                return 0;
            int[] helper = new int[input.length];
            return mergeSort(0, input.length - 1, input, helper);
        }
    
        public static int mergeSort(int low, int high, int[] input, int[] helper) {
            int inversionCount = 0;
            if (low < high) {
                int medium = low + (high - low) / 2;
                inversionCount += mergeSort(low, medium, input, helper);
                inversionCount += mergeSort(medium + 1, high, input, helper);
                inversionCount += merge(low, medium, high, input, helper);
            }
            return inversionCount;
        }
    
        public static int merge(int low, int medium, int high, int[] input, int[] helper) {
            int inversionCount = 0;
    
            for (int i = low; i <= high; i++)
                helper[i] = input[i];
    
            int i = low;
            int j = medium + 1;
            int k = low;
    
            while (i <= medium && j <= high) {
                if (helper[i] <= helper[j]) {
                    input[k] = helper[i];
                    i++;
                } else {
                    input[k] = helper[j];
                    // the number of elements in the first half which the j element needs to jump over.
                    // there is an inversion between each of those elements and j.
                    inversionCount += (medium + 1 - i);
                    j++;
                }
                k++;
            }
    
            // finish writing back in the input the elements from the first part
            while (i <= medium) {
                input[k] = helper[i];
                i++;
                k++;
            }
            return inversionCount;
        }
    
    }
    

提交回复
热议问题