githubEdit

18. Count Inversions

βœ… GFG solution to the Count Inversions problem: find the number of inversion pairs in an array using merge sort, BIT, and segment tree techniques. πŸš€

The problem can be found at the following link: πŸ”— Question Linkarrow-up-right

🧩 Problem Description

Given an array of integers arr[], find the Inversion Count of the array.

An inversion count refers to the number of pairs of elements (i, j) such that i < j and arr[i] > arr[j]. In other words, it measures how far (or close) the array is from being sorted β€” the higher the inversion count, the more unsorted the array is.

πŸ“˜ Examples

Example 1

Input: arr[] = [2, 4, 1, 3, 5]
Output: 3
Explanation: The sequence 2, 4, 1, 3, 5 has three inversions: (2, 1), (4, 1), (4, 3).

Example 2

Input: arr[] = [2, 3, 4, 5, 6]
Output: 0
Explanation: The sequence is already sorted, so there is no inversion count.

Example 3

πŸ”’ Constraints

  • $1 \le \text{arr.size()} \le 10^5$

  • $1 \le \text{arr}[i] \le 10^4$

βœ… My Approach

The optimal approach uses Merge Sort (Divide and Conquer) to count inversions efficiently during the merge step itself:

Modified Merge Sort

  1. Divide: Split the array into two halves recursively until each subarray has one element.

  2. Count During Merge: When merging two sorted halves, if an element from the right half is smaller than an element from the left half, all remaining elements in the left half form inversions with it. Add (mid - left_pointer + 1) to the count.

  3. Merge: Combine the two sorted halves back into a single sorted array using a temporary buffer.

  4. Propagate Count: Return the total inversion count by summing counts from left half, right half, and the merge step.

This piggybacks inversion counting onto the natural comparison process of merge sort, avoiding the need for any separate O(nΒ²) scan.

πŸ“ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n log n), as the array is divided into halves recursively (log n levels) and each merge step processes all n elements linearly, giving O(n log n) total work.

  • Expected Auxiliary Space Complexity: O(n), as a temporary array of size n is required during the merge step to hold elements before placing them back into the original array.

πŸ§‘β€πŸ’» Code (C)

πŸ§‘β€πŸ’» Code (C++)

chevron-right⚑ View Alternative Approaches with Code and Analysishashtag

πŸ“Š 2️⃣ BIT (Binary Indexed Tree / Fenwick Tree) Approach

πŸ’‘ Algorithm Steps:

  1. Coordinate compress the array values to the range [1, n] to make them usable as BIT indices.

  2. Traverse the array from right to left; for each element, query the BIT to get the count of elements already seen that are smaller than the current element β€” each such element forms an inversion.

  3. After querying, update the BIT at the compressed index of the current element.

  4. Accumulate all query results to get the total inversion count.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n log n) β€” Sorting for compression takes O(n log n); each BIT update and query runs in O(log n), done n times.

  • Auxiliary Space: πŸ’Ύ O(n) β€” BIT array and compressed values array each require O(n) space.

βœ… Why This Approach?

  • Elegant point-update range-query pattern used widely in competitive programming.

  • Very fast in practice due to simple bit manipulation operations.

  • Ideal when the array is dynamic or elements arrive in a stream.

πŸ“Š 3️⃣ Segment Tree Approach

πŸ’‘ Algorithm Steps:

  1. Coordinate compress the array values to reduce the value range to [1, m] where m is the number of distinct elements.

  2. Traverse the array left to right; for each element, query the segment tree for the count of already-inserted elements that are strictly greater than the current element β€” these form inversions with the current element.

  3. After querying, update the segment tree at the position of the current compressed value.

  4. Sum all query results to obtain the final inversion count.

πŸ“ Complexity Analysis:

  • Time: ⏱️ O(n log n) β€” Compression takes O(n log n); each segment tree update and range query runs in O(log n), repeated n times.

  • Auxiliary Space: πŸ’Ύ O(n) β€” Segment tree requires 4 Γ— m nodes where m ≀ n, giving O(n) space.

βœ… Why This Approach?

  • Highly flexible β€” easily extends to harder variants like range inversion queries or weighted inversions.

  • Supports both point updates and range sum queries in a unified structure.

  • Solid foundation for more complex problems in competitive programming.

πŸ†š πŸ” Comparison of Approaches

πŸš€ Approach

⏱️ Time Complexity

πŸ’Ύ Space Complexity

βœ… Pros

⚠️ Cons

πŸ”€ Merge Sort

🟒 O(n log n)

🟒 O(n)

πŸš€ Simple, no preprocessing needed

πŸ”§ Modifies input array

🌲 BIT / Fenwick Tree

🟒 O(n log n)

🟑 O(n)

⚑ Fastest in practice, minimal overhead

πŸ”§ Requires coordinate compression

πŸ“ Segment Tree

🟒 O(n log n)

🟑 O(n)

🎯 Most flexible for range variants

🐌 Higher constant factor

πŸ† Best Choice Recommendation

🎯 Scenario

πŸŽ–οΈ Recommended Approach

πŸ”₯ Performance Rating

πŸ… General use / interviews

πŸ₯‡ Merge Sort

β˜…β˜…β˜…β˜…β˜…

⚑ Competitive programming

πŸ₯ˆ BIT / Fenwick Tree

β˜…β˜…β˜…β˜…β˜…

🎯 Complex range inversion variants

πŸ… Segment Tree

β˜…β˜…β˜…β˜…β˜†

β˜• Code (Java)

🐍 Code (Python)

🧠 Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: πŸ“¬ Any Questions?arrow-up-right. Let's make this learning journey more collaborative!

⭐ If you find this helpful, please give this repository a star! ⭐


πŸ“Visitor Count

Visitor counter

Last updated