Given an array of integers arr[]. Find the Inversion Count in the array.
Two elements arr[i] and arr[j] form an inversion if arr[i] > arr[j] and i < j.
Inversion Count: For an array, inversion count indicates how far (or close) the array is from being sorted. If the array is already sorted then the inversion count is 0.
If an array is sorted in the reverse order then the inversion count is the maximum.
Examples:
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).
Input: arr[] = [2, 3, 4, 5, 6]
Output: 0 Explanation: As the sequence is already sorted so there is no inversion count.
Input: arr[] = [10, 10, 10]
Output: 0 Explanation: As all the elements of array are same, so there is no inversion count.
Constraints:
1 ≤ arr.size() ≤ 105
1 ≤ arr[i] ≤ 104
Approach 01:
-
C++
-
Python
class Solution {
public:
int inversionCount(vector<int>& arr) {
auto fenwickUpdate = [](vector<int>& fenwickTree, int index, int delta, int maxValue) {
while (index <= maxValue) {
fenwickTree[index] += delta;
index += index & -index;
}
};
auto fenwickSum = [](vector<int>& fenwickTree, int index) {
int total = 0;
while (index > 0) {
total += fenwickTree[index];
index -= index & -index;
}
return total;
};
int arraySize = arr.size();
int maxValue = *max_element(arr.begin(), arr.end());
// Create a Fenwick Tree of size maxValue + 1
vector<int> fenwickTree(maxValue + 1, 0);
// Start from the rightmost element to count inversions
int inversionCount = 0;
for (int currentIndex = arraySize - 1; currentIndex >= 0; currentIndex--) {
// Count elements smaller than arr[currentIndex]
inversionCount += fenwickSum(fenwickTree, arr[currentIndex] - 1);
// Update the Fenwick Tree with the current element
fenwickUpdate(fenwickTree, arr[currentIndex], 1, maxValue);
}
return inversionCount;
}
};
class Solution:
def inversionCount(self, arr):
def fenwickUpdate(fenwickTree, index, delta, maxValue):
while index <= maxValue:
fenwickTree[index] += delta
index += index & -index
def fenwickSum(fenwickTree, index):
total = 0
while index > 0:
total += fenwickTree[index]
index -= index & -index
return total
arraySize = len(arr)
maxValue = max(arr)
# Create a Fenwick Tree of size maxValue + 1
fenwickTree = [0] * (maxValue + 1)
# Start from the rightmost element to count inversions
inversionCount = 0
for currentIndex in range(arraySize - 1, -1, -1):
# Count elements smaller than arr[currentIndex]
inversionCount += fenwickSum(fenwickTree, arr[currentIndex] - 1)
# Update the Fenwick Tree with the current element
fenwickUpdate(fenwickTree, arr[currentIndex], 1, maxValue)
return inversionCount
Time Complexity
- Initialization:
Finding the maximum value in the array (`maxValue`) using
max_elementtakes \(O(n)\), where \(n\) is the size of the input arrayarr. - Processing each element:
- Each iteration of the loop performs two key operations:
fenwickSum, which computes the prefix sum in a Fenwick Tree. This takes \(O(\log(\text{maxValue}))\) per call.fenwickUpdate, which updates the Fenwick Tree. This also takes \(O(\log(\text{maxValue}))\) per call.
- Since the loop runs \(n\) times, these operations collectively contribute \(O(n \cdot \log(\text{maxValue}))\).
- Each iteration of the loop performs two key operations:
- Overall Time Complexity:
The total time complexity is \(O(n + n \cdot \log(\text{maxValue}))\), where \(n\) is the size of the array, and \(\text{maxValue}\) is the largest element in the array. The \(O(n)\) term comes from initialization, while \(O(n \cdot \log(\text{maxValue}))\) dominates for large inputs.
Space Complexity
- Fenwick Tree:
The Fenwick Tree is a vector of size \(\text{maxValue} + 1\), requiring \(O(\text{maxValue})\) space.
- Auxiliary variables:
The function uses a few integer variables and lambdas, which require \(O(1)\) space.
- Overall Space Complexity:
The total space complexity is \(O(\text{maxValue})\).