-
Notifications
You must be signed in to change notification settings - Fork 3
/
44_Google_Count_Inversions_In_Unsorted_List.py
executable file
·72 lines (50 loc) · 2.13 KB
/
44_Google_Count_Inversions_In_Unsorted_List.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""
This problem was asked by Google.
We can determine how "out of order" an array A is by counting the number of inversions it has.
Two elements A[i] and A[j] form an inversion if A[i] > A[j] but i < j.
That is, a smaller element appears after a larger element.
Given an array, count the number of inversions it has. Do this faster than O(N^2) time.
You may assume each element in the array is distinct.
For example, a sorted list has zero inversions.
The array [2, 4, 1, 3, 5] has three inversions: (2, 1), (4, 1), and (4, 3).
The array [5, 4, 3, 2, 1] has ten inversions: every distinct pair forms an inversion.
"""
# idea: use merge sort to count the number of inversions:
# Runtime of merge sort is O(n*log(n)) which is less than O(n^2)
def merge(list_a_with_inv_tuple, list_b_with_inv_tuple):
merged_list = []
list_a, invs_in_a = list_a_with_inv_tuple
list_b, invs_in_b = list_b_with_inv_tuple
len_a = len(list_a)
len_b = len(list_b)
inversions = invs_in_a + invs_in_b
iter_a, iter_b = 0, 0
while iter_a < len_a and iter_b < len_b:
if list_a[iter_a] < list_b[iter_b]:
merged_list.append(list_a[iter_a])
iter_a += 1
else:
merged_list.append(list_b[iter_b])
# the num "list_b[iter_b]" must be less than all the values list_a[iter_a:]
inversions += len(list_a[iter_a:])
iter_b += 1
# append the remaining number to the list
while iter_a < len_a:
merged_list.append(list_a[iter_a])
iter_a += 1
while iter_b < len_b:
merged_list.append(list_b[iter_b])
iter_b += 1
return merged_list, inversions
def merge_sort(list):
# if list only contains one number than just return the list and 0 inversions
if len(list) == 1:
return list, 0
# otherwise, divide list into two and run merge sort on tow smaller lists
mid = len(list)//2
return merge(merge_sort(list[:mid]), merge_sort(list[mid:]))
def count_inversions(list):
_, inversions = merge_sort(list)
return inversions
if __name__ == '__main__':
assert count_inversions(list=[2, 4, 1, 3, 5]) ==3