The problem. Given an array nums, count its inversions: pairs of indexes i < j with nums[i] > nums[j]. The count measures how far the array is from sorted — 0 for a sorted array, n(n − 1)/2 for a reversed one.
nums = [2, 4, 1, 3, 5] -> 3 (2>1, 4>1, 4>3)
nums = [5, 4, 3, 2, 1] -> 10
nums = [1, 2, 3, 4] -> 0Split the array in half. Every inversion is either inside the left half, inside the right half, or across (left value bigger than a right value). The first two are counted recursively. For the third, sort both halves — merge sort does that anyway — and look at the merge: when the merge takes a[j] from the right half because it's smaller than a[i], it's also smaller than every value still waiting in the left half (they're sorted, all at least a[i]). That's mid − i inversions counted in one step, instead of one at a time.
function countInversions(nums) { let count = 0; for (let i = 0; i < nums.length; i++) { for (let j = i + 1; j < nums.length; j++) { if (nums[i] > nums[j]) count++; } } return count;}Time O(n²), space O(1).
Each time the merge takes a value from the right half, add how many values are still waiting on the left.
function countInversions(nums) { const a = [...nums]; const sortCount = (lo, hi) => { // sorts a[lo..hi), returns the inversions inside it if (hi - lo <= 1) return 0; const mid = (lo + hi) >> 1; let count = sortCount(lo, mid) + sortCount(mid, hi); const merged = []; let i = lo, j = mid; while (i < mid && j < hi) { if (a[i] <= a[j]) merged.push(a[i++]); else { count += mid - i; // a[j] is smaller than everything left in the left half merged.push(a[j++]); } } while (i < mid) merged.push(a[i++]); while (j < hi) merged.push(a[j++]); for (let k = 0; k < merged.length; k++) a[lo + k] = merged[k]; return count; }; return sortCount(0, a.length);}Time O(n log n), space O(n). It's merge sort with one extra addition, so it costs the same. Use a 64-bit counter: n = 10⁵ can have about 5 × 10⁹ inversions. And <= matters — equal values are not an inversion, so a tie takes from the left without counting.
Inversions also measure work: insertion sort and bubble sort make exactly one swap or shift per inversion.
[2, 2] has 0 inversions.