Skip to content

feat: Add CountingInversions new algorithm with Junit tests #5745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@
* divideandconquer
* [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
* [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
* [CountingInversions](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/CountingInversions.java)
* [MedianOfTwoSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java)
* [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
* [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
Expand Down Expand Up @@ -833,6 +834,7 @@
* divideandconquer
* [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java)
* [ClosestPairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java)
* [CountingInversionsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java)
* [MedianOfTwoSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java)
* [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java)
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.thealgorithms.divideandconquer;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class CountingInversionsTest {

@Test
public void testCountInversions() {
int[] arr = {2, 3, 8, 6, 1};
assertEquals(5, CountingInversions.countInversions(arr));
}

@Test
public void testNoInversions() {
int[] arr = {1, 2, 3, 4, 5};
assertEquals(0, CountingInversions.countInversions(arr));
}

@Test
public void testSingleElement() {
int[] arr = {1};
assertEquals(0, CountingInversions.countInversions(arr));
}

@Test
public void testAllInversions() {
int[] arr = {5, 4, 3, 2, 1};
assertEquals(10, CountingInversions.countInversions(arr));
}
}