Count Inversions in Array in DSA Python - Time & Space Complexity
We want to understand how long it takes to count inversions in an array as the array grows.
Specifically, how does the work increase when the array size gets bigger?
Analyze the time complexity of the following code snippet.
def merge_sort_count(arr):
if len(arr) <= 1:
return arr, 0
mid = len(arr) // 2
left, left_inv = merge_sort_count(arr[:mid])
right, right_inv = merge_sort_count(arr[mid:])
merged, split_inv = merge_count(left, right)
return merged, left_inv + right_inv + split_inv
# merge_count merges two sorted arrays and counts split inversions
This code counts how many pairs of elements are out of order by using a merge sort approach.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive splitting and merging of the array.
- How many times: The array is split into halves repeatedly until size 1, then merged back.
Each split divides the array in half, and merging compares elements to count inversions.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 50 comparisons and merges |
| 100 | About 700 comparisons and merges |
| 1000 | About 10,000 comparisons and merges |
Pattern observation: The work grows roughly by n times log n.
Time Complexity: O(n log n)
This means the time to count inversions grows a little more than linearly, because we split and merge repeatedly.
[X] Wrong: "Counting inversions must be O(n²) because we compare every pair."
[OK] Correct: The merge sort method cleverly counts inversions during merging, avoiding checking all pairs directly.
Understanding this method shows you can improve naive solutions by using smart divide-and-conquer techniques.
"What if we used a simple nested loop to count inversions? How would the time complexity change?"
Practice
inversion in an array mean?Solution
Step 1: Understand the definition of inversion
An inversion is when a larger number appears before a smaller number in the array.Step 2: Compare options with definition
A pair of elements where the first is greater than the second and appears before it correctly describes this pair condition, others do not.Final Answer:
A pair of elements where the first is greater than the second and appears before it -> Option BQuick Check:
Inversion = larger before smaller [OK]
- Confusing inversion with sorted order
- Thinking inversion counts equal elements
- Mixing up element positions
Solution
Step 1: Check the loop ranges and condition
count = 0 for i in range(len(arr)): for j in range(i+1, len(arr)): if arr[i] > arr[j]: count += 1 loops i from 0 to end and j from i+1 to end, comparing arr[i] > arr[j]. This matches inversion definition.Step 2: Verify other options
count = 0 for i in range(len(arr)): for j in range(i): if arr[i] > arr[j]: count += 1 checks arr[i] > arr[j] but loops j before i, counting later > earlier which is incorrect. count = 0 for i in range(len(arr)): for j in range(i+1, len(arr)): if arr[i] < arr[j]: count += 1 counts when arr[i] < arr[j], which is not inversion. count = 0 for i in range(len(arr)): for j in range(i+1, len(arr)): if arr[i] == arr[j]: count += 1 counts equal elements, not inversions.Final Answer:
count = 0 for i in range(len(arr)): for j in range(i+1, len(arr)): if arr[i] > arr[j]: count += 1 -> Option AQuick Check:
Nested loops with arr[i] > arr[j] count inversions [OK]
- Checking arr[i] < arr[j] instead of >
- Looping j before i
- Counting equal elements as inversions
def count_inversions(arr):
count = 0
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if arr[i] > arr[j]:
count += 1
return count
print(count_inversions([2, 4, 1, 3, 5]))Solution
Step 1: Identify all inversion pairs in the array
Array: [2, 4, 1, 3, 5]. Inversions are (2,1), (4,1), (4,3). Total 3 inversions.Step 2: Confirm code counts these correctly
Code loops through pairs and increments count for each inversion found, so returns 3.Final Answer:
3 -> Option DQuick Check:
Count inversions in [2,4,1,3,5] = 3 [OK]
- Missing some inversion pairs
- Counting pairs with equal elements
- Confusing order of pairs
def count_inversions(arr):
count = 0
for i in range(len(arr)):
for j in range(i):
if arr[i] > arr[j]:
count += 1
return count
print(count_inversions([3, 1, 2]))Solution
Step 1: Analyze loop ranges and comparison
Inner loop runs j from 0 to i-1, so j < i. The code checks if arr[i] > arr[j], counting pairs where later element is bigger.Step 2: Identify correct inversion condition
Inversion means earlier element is bigger than later one, so condition should be arr[j] > arr[i]. Current condition is reversed, causing wrong count.Final Answer:
The comparison should be arr[i] < arr[j] instead of arr[i] > arr[j] -> Option CQuick Check:
Inversion needs earlier > later, fix comparison [OK]
- Reversing comparison operator
- Wrong loop ranges causing missed pairs
- Not returning count
[8, 4, 2, 1], what is the number of inversions? Also, explain why this count represents the worst case for inversion counting algorithms.Solution
Step 1: Count all inversion pairs in the array
Array: [8, 4, 2, 1]. Inversions: (8,4), (8,2), (8,1), (4,2), (4,1), (2,1) = 6 total.Step 2: Explain why this is worst case
Array sorted descending means every pair is inverted. Algorithms checking pairs must count all, causing maximum work.Final Answer:
6; because the array is sorted in descending order, all pairs are inversions -> Option AQuick Check:
Descending array has max inversions = n(n-1)/2 [OK]
- Counting only adjacent pairs
- Confusing ascending with descending
- Not recognizing worst case scenario
Ready to prove it?
Pass the test and this pattern moves unknown
