mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-06 00:54:32 +08:00
Add CountingInversions
algorithm (#5745)
This commit is contained in:
@ -0,0 +1,101 @@
|
||||
package com.thealgorithms.divideandconquer;
|
||||
|
||||
/**
|
||||
* A utility class for counting the number of inversions in an array.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Time Complexity: O(n log n)
|
||||
* Space Complexity: O(n) (due to temporary arrays during merge step)
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user