倒置个数
又名:逆序对的个数
题目描述
Description
有一个由N个实数构成的数组,如果一对元素A[i]和A[j]是倒序的,即i<j但是A[i]>A[j]则称它们是一个倒置,设计一个计算该数组中所有倒置数量的算法。要求算法复杂度为O(nlogn)
Input
输入有多行,第一行整数T表示为测试用例个数,后面是T个测试用例,每一个用例包括两行,第一行的一个整数是元素个数,第二行为用空格隔开的数组值。
Output
输出每一个用例的倒置个数,一行表示一个用例。
Sample Input 1
1
8
8 3 2 9 7 1 5 4
Sample Output 1
17
题目解析
就是在并归排序的基础上统计一下逆序数的个数.
即:分别求出左半边的逆序数和右半边的逆序数,并求和统计
如何求逆序数?
- 左数组和右数组都是相对有序的,如果右数组的数小于左数组的数(此时构成逆序),则跟左数组中所有大于该数的数(排列在该数的右面)都构成逆序
例子
[8 3] num+=1 --> [3 8]
[2 9] num+=0 --> [2 9]
此时左数组为[3 8] 右数组为 [2 9]
此时 2 < 3 构成一个逆序,则 2与左数组中所有大于3的数都构成逆序, 因此num += 2
代码实现
def merge(l_arr, r_arr, num):
res_arr = []
i, j = 0, 0
while i < len(l_arr) and j < len(r_arr):
if l_arr[i] <= r_arr[j]: # 这里面是小于等于,经过排查已经纠错
res_arr.append(l_arr[i])
i += 1
else:
res_arr.append(r_arr[j])
num += len(l_arr) - i # 多了一行代码,用来统计个数
j += 1
if i < len(l_arr):
res_arr = res_arr + l_arr[i:]
if j < len(r_arr):
res_arr = res_arr + r_arr[j:]
return res_arr, num
def merge_sort(arr):
if len(arr) <= 1:
return arr, 0 # 多返回一个指,用来统计倒置个数
m = len(arr) >> 1
l_arr, l_num = merge_sort(arr[:m])
r_arr, r_num = merge_sort(arr[m:])
return merge(l_arr, r_arr, (l_num + r_num)) # 倒置个数求和
if __name__ == '__main__':
case_num = int(input().strip())
for i in range(case_num):
_ = input()
arr = [int(x) for x in input().strip().split(" ")]
_, num = merge_sort(arr)
print(num)