Given an array:
arr = [2,3,1,4]
I could write a count inversion array such that counting all numbers n2
after a certain number n1
in arr
such that n1
> n2
and write it like this
[1 1 0 0]
Similarly, the inversion array of:
[2, 1, 4, 3]
would be:
[1, 0, 1, 0]
For:
[20]
[1, 2, 3, 4, 5, 6]
[87, 78, 16, 94]
Output would be:
0
0 0 0 0 0 0
2 1 0 0
Constraints:
- \$1 \le N \le 10^4\$
- \$1 \le i \le 10^6\$
The code that I wrote works for most cases but takes >10sec for an extra large number of test cases.
from copy import copy
def merge(arr, left_lo, left_hi, right_lo, right_hi, dct):
startL = left_lo
startR = right_lo
N = left_hi-left_lo + 1 + right_hi - right_lo + 1
aux = [0] * N
res = []
for i in xrange(N):
if startL > left_hi:
aux[i] = arr[startR]
startR += 1
elif startR > right_hi:
aux[i] = arr[startL]
startL += 1
elif arr[startL] <= arr[startR]:
aux[i] = arr[startL]
startL += 1
# print aux
else:
aux[i] = arr[startR]
res.append(startL)
startR += 1
# print aux
for index in res:
for x in xrange(index, left_hi+1):
dct[arr[x]] += 1
for i in xrange(left_lo, right_hi+1):
arr[i] = aux[i - left_lo]
return
def merge_sort(arr, lo, hi, dct):
mid = (lo+hi)/2
if lo<=mid<hi:
merge_sort(arr, lo, mid, dct)
merge_sort(arr, mid+1, hi, dct)
merge(arr, lo, mid, mid+1, hi, dct)
return
def count_inversion(arr, N):
lo = 0
hi = N-1
dct = {i:0 for i in arr}
arr2 = copy(arr)
merge_sort(arr, lo, hi, dct)
return ' '.join([str(dct[num]) for num in arr2])
count_inversion
calls merge_sort
and that's where the total number of LEFT > RIGHT inversions are incremented. All numbers are stored in a dictionary with counts such that whenever L > R occurs all numbers in the left array starting from L to end of Left array are incremented by 1.
Now I understand there could be a way to optimize this snippet:
for index in res:
for x in xrange(index, left_hi+1):
dct[arr[x]] += 1
/
should be//
inmerge_sort()
. Otherwise: RuntimeError: maximum recursion depth exceeded. \$\endgroup\$