Skip to content
← Back to all questions
FreeCodingMedium

Counting Inversions in an Array

Asked atCitadel SecuritiesJane StreetDRW

Question

Given an array aa of nn distinct integers, an inversion is a pair of indices i<ji < j with ai>aja_i > a_j.

Count the inversions in O(nlog⁡n)O(n \log n) time. Then explain what the inversion count measures statistically.

Solution

Try it yourself first. Open a hint if you get stuck.

Show solution

Approach — merge sort with a counter. During the merge of two sorted halves, when an element from the right half is emitted ahead of kk remaining elements in the left half, those kk elements each form an inversion with it. Accumulate as you merge.

def count_inversions(a):
    def sort_count(xs):
        if len(xs) <= 1:
            return xs, 0
        mid = len(xs) // 2
        left, cl = sort_count(xs[:mid])
        right, cr = sort_count(xs[mid:])
        merged, cm = [], 0
        i = j = 0
        while i < len(left) and j < len(right):
            if left[i] <= right[j]:
                merged.append(left[i]); i += 1
            else:
                merged.append(right[j]); j += 1
                cm += len(left) - i      # all remaining left elems invert
        merged += left[i:] + right[j:]
        return merged, cl + cr + cm
    return sort_count(a)[1]

Recurrence T(n)=2T(n/2)+O(n)T(n) = 2T(n/2) + O(n) gives O(nlog⁡n)O(n \log n) time and O(n)O(n) space.

Alternative. Compress values to ranks and sweep right-to-left with a Binary Indexed Tree, querying the count of already-seen smaller values. Same complexity, often preferred when the array is streaming.

The statistical connection — this is the real question. The inversion count II is exactly the unnormalised version of Kendall's tau:

τ=1−4In(n−1).\tau = 1 - \frac{4I}{n(n-1)}.

So an O(nlog⁡n)O(n\log n) inversion counter is an O(nlog⁡n)O(n\log n) rank-correlation estimator. That matters in practice because Kendall's tau is robust to outliers and monotone transformations in a way Pearson correlation is not — which is why it shows up when scoring a signal against forward returns on heavy-tailed data.

Edge cases to mention: ties (decide ≤\le vs << and stay consistent; ties need the tau-b correction), and overflow — II can reach (n2)\binom{n}{2}, so use 64-bit.