Skip to content
dsa450for five year olds

Searching & Sorting · 34 of 36

Find the inversion count

Count how many pairs in a line are in the wrong order, with a bigger number standing before a smaller one.

Simple way
time O(n^2)
room O(1)
Clever way
time O(n log n)
room O(n)

The problem, simply

You get an array of numbers. A pair of positions i < j is out of order when arr[i] > arr[j]: a bigger number stands before a smaller one. Each such pair is an inversion.

Count them all. A sorted array has 0. An array sorted backwards has the most, n * (n - 1) / 2. The count tells you how far the array is from sorted.

A story to remember it

Picture it

array
0123453816
setout of order pairs
(5, 3)(5, 1)(3, 1)(8, 1)(8, 6)

Five out of order pairs in [5, 3, 8, 1, 6]: (5, 3), (5, 1), (3, 1), (8, 1) and (8, 6).

Examples

A normal case

In
[5, 3, 8, 1, 6]
Out
5

The five pairs listed above. The walkthrough counts them with merge sort.

The classic one

In
[2, 4, 1, 3, 5]
Out
3

(2, 1), (4, 1) and (4, 3).

Already sorted

In
[1, 2, 3, 4, 5]
Out
0

Nobody stands before a smaller number.

Sorted backwards

In
[5, 4, 3, 2, 1]
Out
10

Every pair is out of order: 5 * 4 / 2 = 10.

Equal numbers

In
[2, 2, 1]
Out
2

Each 2 pairs with the 1. The two 2s are not out of order, because the rule says strictly bigger.

Way 1: the simple way

Check every pair. For each i, look at every later j and count when arr[i] > arr[j].

java
class Solution {
    public long inversionCount(long[] arr) {
        long count = 0;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[i] > arr[j]) count++;   // bigger one stands first
            }
        }
        return count;
    }
}

How long it takes: about n * n / 2 pair checks, O(n^2). With half a million numbers that is over a hundred billion checks. Extra room: O(1).

Way 2: the clever way

Every out of order pair is one of three kinds: both numbers in the left half, both in the right half, or one in each half. Merge sort already splits the array this way. So:

  1. Split in the middle. Count (and sort) the left half. Count (and sort) the right half. The smaller sorts do this by splitting again.
  2. Merge the two sorted halves with fingers i (left) and j (right).
  3. If left[i] <= right[j], the left number goes down first. No new pairs.
  4. If right[j] is smaller, it goes down first, and every left number from i to the end of the left half is bigger and stood before it. Add mid - i + 1 at once.

The tree shows the pieces. Each piece's note says how many pairs its merge found.

Count the pairs while merge sort merges

01 / 14

treesplit and merge
5 3 8 1 65 3 85 35381 616

Cut the line in half again and again until every piece has one number. A single number has no out of order pairs.

total
0
  • looking now
  • done
  • answer
  • rejected
  • just added
java
class Solution {
    public long inversionCount(long[] arr) {
        if (arr.length < 2) return 0;
        return sortAndCount(arr, new long[arr.length], 0, arr.length - 1);
    }

    private long sortAndCount(long[] a, long[] tmp, int lo, int hi) {
        if (lo >= hi) return 0;                      // one number, no pairs
        int mid = lo + (hi - lo) / 2;
        long count = sortAndCount(a, tmp, lo, mid);  // pairs inside the left half
        count += sortAndCount(a, tmp, mid + 1, hi);  // pairs inside the right half
        int i = lo, j = mid + 1, k = lo;
        while (i <= mid && j <= hi) {
            if (a[i] <= a[j]) {
                tmp[k++] = a[i++];                   // left goes first, no new pairs
            } else {
                count += mid - i + 1;                // every waiting left number is bigger
                tmp[k++] = a[j++];
            }
        }
        while (i <= mid) tmp[k++] = a[i++];
        while (j <= hi) tmp[k++] = a[j++];
        for (k = lo; k <= hi; k++) a[k] = tmp[k];
        return count;
    }
}

How long it takes: the array is halved about log n times, and each level of merging touches every number once: O(n log n). Extra room: the helper array, O(n), plus O(log n) for waiting calls.

Watch out for

  • The count can reach about n^2 / 2, over a hundred billion for half a million numbers. Use long for the count.
  • The values themselves can be huge on GeeksforGeeks (up to 10^18), so store them in long[].
  • Add mid - i + 1 (all waiting left numbers), not 1.
  • The method sorts the input. Copy it first if the caller needs the original order.

What interviewers ask next

  • Another O(n log n) way? A Fenwick tree (binary indexed tree): walk from right to left, ask how many smaller numbers you have already seen, then add this one. Squash big values into ranks first.
  • What does the count mean? It equals the number of swaps bubble sort or insertion sort makes, and the fewest swaps of neighbours needed to sort the array.
  • Count pairs with arr[i] > 2 * arr[j] (LeetCode 493, reverse pairs). Same merge sort, but count with a separate finger pass before the merge, since the count rule and the merge rule differ.
  • For each number, how many smaller numbers are on its right (LeetCode 315)? Same merge, but track original positions and add the count to each left number as it goes down.
  • How similar are two rankings? Relabel one ranking by the other and count inversions. That is the Kendall tau distance.

Remember this

Grown-up words: an out of order pair is an inversion, splitting and merging is merge sort (divide and conquer), pairs across the two halves are split inversions, and the helper array is the auxiliary buffer.