|
| 1 | +""" |
| 2 | +Count Inversions in an array using a modified Merge Sort algorithm. |
| 3 | +
|
| 4 | +An inversion is a pair of indices (i, j) such that: |
| 5 | + - i < j |
| 6 | + - arr[i] > arr[j] |
| 7 | +This represents a disorder in the array relative to a sorted order. |
| 8 | +
|
| 9 | +This implementation efficiently counts the number of such inversions |
| 10 | +in O(n log n) time by modifying the merge step of Merge Sort. |
| 11 | +
|
| 12 | +Use Cases: |
| 13 | +---------- |
| 14 | +- Measuring how far a sequence is from being sorted. |
| 15 | +- Evaluating disorder in datasets (e.g., in rankings or sequences). |
| 16 | +- Useful in computer vision, bioinformatics, and comparison of lists. |
| 17 | +- Core concept in Kendall tau distance and other similarity metrics. |
| 18 | +""" |
| 19 | +def count_inversions(arr): |
| 20 | + def merge_sort(arr): |
| 21 | + if len(arr) <= 1: |
| 22 | + return arr, 0 |
| 23 | + |
| 24 | + mid = len(arr) // 2 |
| 25 | + left, inv_left = merge_sort(arr[:mid]) |
| 26 | + right, inv_right = merge_sort(arr[mid:]) |
| 27 | + merged, inv_split = merge(left, right) |
| 28 | + |
| 29 | + total_inversions = inv_left + inv_right + inv_split |
| 30 | + return merged, total_inversions |
| 31 | + |
| 32 | + def merge(left, right): |
| 33 | + i = j = inv_count = 0 |
| 34 | + merged = [] |
| 35 | + |
| 36 | + while i < len(left) and j < len(right): |
| 37 | + if left[i] <= right[j]: |
| 38 | + merged.append(left[i]) |
| 39 | + i += 1 |
| 40 | + else: |
| 41 | + merged.append(right[j]) |
| 42 | + j += 1 |
| 43 | + inv_count += len(left) - i # All remaining in left > right[j] |
| 44 | + |
| 45 | + merged += left[i:] |
| 46 | + merged += right[j:] |
| 47 | + return merged, inv_count |
| 48 | + |
| 49 | + _, total_inversions = merge_sort(arr) |
| 50 | + return total_inversions |
| 51 | + |
| 52 | + |
| 53 | +# Example usage |
| 54 | +if __name__ == "__main__": |
| 55 | + sample = [2, 4, 1, 3, 5] |
| 56 | + print(f"Inversion count: {count_inversions(sample)}") |
0 commit comments