题目描述
给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。
逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i < j 且 a[i] > a[j],则其为一个逆序对;否则不是。
输入格式
第一行包含整数n,表示数列的长度。
第二行包含 n 个整数,表示整个数列。
输出格式
输出一个整数,表示逆序对的个数。
数据范围
1≤n≤100000
输入样例:
6
2 3 4 5 6 1
输出样例:
5
观众老爷们,如果本思路对您有帮助,求关注一波~~~
思路
在两个区间合并过程中,出现逆序对的情况只能在两个区间进行数值的比较
初始, 逆序对的个数为res = 0
举例
[l, mid] 1, 2, 4, 4 l = 0 mid = 3
[mid + 1, r] 2, 3, 4, 5, mid + 1 = 4 r = 7
i j
1. 1(1) < 2(4) tmp = [1] res = 0
2. 2(2) <= 2(4) tmp = [1, 2] res = 0
3. 4(3) > 2(4) tmp = [1, 2, 2] res += 3 - 2 + 1 = 2 左边区间是有序的 对于当前点2, 左区间比4大的元素也 > 2,所以 res = mid - i + 1
4. 4(3) > 3(5) tmp = [1, 2, 2, 3] res += 3 - 2 + 1 = 4
5. 4(3) <= 4(6) tmp = [1, 2, 2, 3, 4] res = 4
6. 4(4) <= 4(6) tmp = [1, 2, 2, 3, 4, 4] res = 4 i遍历完成,很容易发现在右区间剩余元素4, 5必然大于左区间最后一个元素,无法构成逆序对
7.将剩余元素添加到tmp tmp = [1, 2, 2, 3, 4, 4, 4, 5]
8.更新tmp数组到原数组的[1, r]区间,这里也变相的说明了为什么左右区间一开始就是有序的
LL merge_sort(int l, int r){
if(l >= r) return 0;
int mid = l + r >> 1;
LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);
int k = 0, i = l, j = mid + 1;
while(i <= mid && j <= r){
if(q[i] <= q[j]) tmp[k ++] = q[i ++];
else {
tmp[k ++] = q[j ++];
//q[j] > q[i],对于q[j],mid的左边有mid - i + 1个数与q[j]组成逆序对
res += mid - i + 1;
}
}
while(i <= mid) tmp[k ++] = q[i ++];
while(j <= r) tmp[k ++] = q[j ++];
for(int i = l, k = 0; i <= r; i ++, k ++) q[i] = tmp[k];
return res;
}
java 代码
import java.util.Scanner;
public class Main{
static int n;
static int N = 100010;
static int[] q = new int[N], tmp = new int[N];
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for(int i = 0; i < n; i ++) q[i] = sc.nextInt();
long res = mergeSort(q, 0, n - 1);
System.out.println(res);
}
public static long mergeSort(int[] q, int l, int r){
if(l >= r) return 0;
int mid = l + r >> 1;
long res = mergeSort(q, l, mid) + mergeSort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
while(i <= mid && j <= r){
if(q[i] <= q[j]) tmp[k ++] = q[i ++];
else{
res += mid - i + 1;
tmp[k ++] = q[j ++];
}
}
while(i <= mid) tmp[k ++] = q[i ++];
while(j <= r) tmp[k ++] = q[j ++];
for(i = l, k = 0; i <= r; i ++, k ++) q[i] = tmp[k];
return res;
}
}
python3 代码
q = [0] * 100010
tmp = [0] * 100010
def mergeSort(q, l, r):
if(l >= r): return 0
mid = l + r >> 1
res = mergeSort(q, l, mid) + mergeSort(q, mid+1, r)
k = 0; i = l; j = mid + 1
while(i <= mid and j <= r):
if(q[i] <= q[j]):
tmp[k] = q[i]
k += 1; i += 1
else:
res += mid - i + 1
tmp[k] = q[j]
k += 1; j += 1
while(i <= mid):
tmp[k] = q[i]
k += 1; i += 1
while(j <= r):
tmp[k] = q[j]
k += 1; j += 1
k = 0; i = l
while(i <= r):
q[i] = tmp[k]
i += 1; k += 1
return res
def main():
global q
n = int(input())
q = list(map(int, input().split()))
res = mergeSort(q, 0, n - 1)
print(res)
main()
C++ 代码
#include
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
int n;
int q[N], tmp[N];
LL merge_sort(int l, int r){
if(l >= r) return 0;
int mid = l + r >> 1;
LL res = merge_sort(l, mid) + merge_sort(mid + 1, r);
int k = 0, i = l, j = mid + 1;
while(i <= mid && j <= r){
if(q[i] <= q[j]) tmp[k ++] = q[i ++];
else {
tmp[k ++] = q[j ++];
//q[j] > q[i],对于q[j],mid的左边有mid - i + 1个数与q[j]组成逆序对
res += mid - i + 1;
}
}
while(i <= mid) tmp[k ++] = q[i ++];
while(j <= r) tmp[k ++] = q[j ++];
for(int i = l, k = 0; i <= r; i ++, k ++) q[i] = tmp[k];
return res;
}
int main(){
cin >> n;
for(int i = 0; i < n; i ++) cin >> q[i];
cout << merge_sort(0, n - 1) << endl;
return 0;
}