package com.thealgorithms.divideandconquer; /** * A utility class for counting the number of inversions in an array. *
* An inversion is a pair (i, j) such that i < j and arr[i] > arr[j]. * This class implements a divide-and-conquer approach, similar to merge sort, * to count the number of inversions efficiently. *
* Time Complexity: O(n log n) * Space Complexity: O(n) (due to temporary arrays during merge step) * *
Applications: * - Used in algorithms related to sorting and permutation analysis. * - Helps in determining how far an array is from being sorted. * - Applicable in bioinformatics and signal processing. * *
This class cannot be instantiated, as it is intended to provide * only static utility methods. * * @author Hardvan */ public final class CountingInversions { private CountingInversions() { } /** * Counts the number of inversions in the given array. * * @param arr The input array of integers. * @return The total number of inversions in the array. */ public static int countInversions(int[] arr) { return mergeSortAndCount(arr, 0, arr.length - 1); } /** * Recursively divides the array into two halves, sorts them, and counts * the number of inversions. Uses a modified merge sort approach. * * @param arr The input array. * @param left The starting index of the current segment. * @param right The ending index of the current segment. * @return The number of inversions within the segment [left, right]. */ private static int mergeSortAndCount(int[] arr, int left, int right) { if (left >= right) { return 0; } int mid = left + (right - left) / 2; int inversions = 0; inversions += mergeSortAndCount(arr, left, mid); inversions += mergeSortAndCount(arr, mid + 1, right); inversions += mergeAndCount(arr, left, mid, right); return inversions; } /** * Merges two sorted subarrays and counts the cross-inversions between them. * A cross-inversion occurs when an element from the right subarray is * smaller than an element from the left subarray. * * @param arr The input array. * @param left The starting index of the first subarray. * @param mid The ending index of the first subarray and midpoint of the segment. * @param right The ending index of the second subarray. * @return The number of cross-inversions between the two subarrays. */ private static int mergeAndCount(int[] arr, int left, int mid, int right) { int[] leftArr = new int[mid - left + 1]; int[] rightArr = new int[right - mid]; System.arraycopy(arr, left, leftArr, 0, mid - left + 1); System.arraycopy(arr, mid + 1, rightArr, 0, right - mid); int i = 0; int j = 0; int k = left; int inversions = 0; while (i < leftArr.length && j < rightArr.length) { if (leftArr[i] <= rightArr[j]) { arr[k++] = leftArr[i++]; } else { arr[k++] = rightArr[j++]; inversions += mid + 1 - left - i; } } while (i < leftArr.length) { arr[k++] = leftArr[i++]; } while (j < rightArr.length) { arr[k++] = rightArr[j++]; } return inversions; } }