2
2
Given an array-like data structure A[1..n], how many pairs
3
3
(i, j) for all 1 <= i < j <= n such that A[i] > A[j]? These pairs are
4
4
called inversions. Counting the number of such inversions in an array-like
5
- object is the important. Among other things, counting inversions can help
6
- us determine how close a given array is to being sorted
7
-
5
+ object is the important. Among other things, counting inversions can help
6
+ us determine how close a given array is to being sorted.
8
7
In this implementation, I provide two algorithms, a divide-and-conquer
9
8
algorithm which runs in nlogn and the brute-force n^2 algorithm.
10
-
11
9
"""
12
10
13
11
14
12
def count_inversions_bf (arr ):
15
13
"""
16
14
Counts the number of inversions using a a naive brute-force algorithm
17
-
18
15
Parameters
19
16
----------
20
17
arr: arr: array-like, the list containing the items for which the number
21
18
of inversions is desired. The elements of `arr` must be comparable.
22
-
23
19
Returns
24
20
-------
25
21
num_inversions: The total number of inversions in `arr`
26
-
27
22
Examples
28
23
---------
29
-
30
24
>>> count_inversions_bf([1, 4, 2, 4, 1])
31
25
4
32
26
>>> count_inversions_bf([1, 1, 2, 4, 4])
@@ -49,20 +43,16 @@ def count_inversions_bf(arr):
49
43
def count_inversions_recursive (arr ):
50
44
"""
51
45
Counts the number of inversions using a divide-and-conquer algorithm
52
-
53
46
Parameters
54
47
-----------
55
48
arr: array-like, the list containing the items for which the number
56
49
of inversions is desired. The elements of `arr` must be comparable.
57
-
58
50
Returns
59
51
-------
60
52
C: a sorted copy of `arr`.
61
53
num_inversions: int, the total number of inversions in 'arr'
62
-
63
54
Examples
64
55
--------
65
-
66
56
>>> count_inversions_recursive([1, 4, 2, 4, 1])
67
57
([1, 1, 2, 4, 4], 4)
68
58
>>> count_inversions_recursive([1, 1, 2, 4, 4])
@@ -72,40 +62,34 @@ def count_inversions_recursive(arr):
72
62
"""
73
63
if len (arr ) <= 1 :
74
64
return arr , 0
75
- else :
76
- mid = len (arr ) // 2
77
- P = arr [0 :mid ]
78
- Q = arr [mid :]
65
+ mid = len (arr ) // 2
66
+ P = arr [0 :mid ]
67
+ Q = arr [mid :]
79
68
80
- A , inversion_p = count_inversions_recursive (P )
81
- B , inversions_q = count_inversions_recursive (Q )
82
- C , cross_inversions = _count_cross_inversions (A , B )
69
+ A , inversion_p = count_inversions_recursive (P )
70
+ B , inversions_q = count_inversions_recursive (Q )
71
+ C , cross_inversions = _count_cross_inversions (A , B )
83
72
84
- num_inversions = inversion_p + inversions_q + cross_inversions
85
- return C , num_inversions
73
+ num_inversions = inversion_p + inversions_q + cross_inversions
74
+ return C , num_inversions
86
75
87
76
88
77
def _count_cross_inversions (P , Q ):
89
78
"""
90
79
Counts the inversions across two sorted arrays.
91
80
And combine the two arrays into one sorted array
92
-
93
81
For all 1<= i<=len(P) and for all 1 <= j <= len(Q),
94
82
if P[i] > Q[j], then (i, j) is a cross inversion
95
-
96
83
Parameters
97
84
----------
98
85
P: array-like, sorted in non-decreasing order
99
86
Q: array-like, sorted in non-decreasing order
100
-
101
87
Returns
102
88
------
103
89
R: array-like, a sorted array of the elements of `P` and `Q`
104
90
num_inversion: int, the number of inversions across `P` and `Q`
105
-
106
91
Examples
107
92
--------
108
-
109
93
>>> _count_cross_inversions([1, 2, 3], [0, 2, 5])
110
94
([0, 1, 2, 2, 3, 5], 4)
111
95
>>> _count_cross_inversions([1, 2, 3], [3, 4, 5])
0 commit comments