数组中的逆序对(分治)
- 题目描述:
- 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
- 输入:
-
每个测试案例包括两行:第一行包含一个整数n,表示数组中的元素个数。其中1 <= n <= 10^5。第二行包含n个整数,每个数组均为int类型。
- 输出:
- 对应每个测试案例,输出一个整数,表示数组中的逆序对的总数。
- 样例输入:
-
4 7 5 6 4
- 样例输出:
-
5
1.直接的做法是逐个统计,复杂度是N^2,
2.可以利用归并排序的思想,在排序过程中统计逆序对的个数。时间复杂度依然是 N*Log(N)。 可以从代码中看到,只是比归并排序多了一句代码:cnt += (n1 - i);
由于最终个数可能超过int,这里用long long
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 long long mergeAndCount(int arr[], int l, int m, int r){ 7 long long cnt = 0; 8 int n1 = m - l + 1; 9 int n2 = r - m; 10 int i, j, k; 11 int L[n1], R[n2]; 12 for(i = 0; i < n1; i++){ 13 L[i] = arr[l + i]; 14 } 15 for(i = 0; i < n2; i++){ 16 R[i] = arr[m + 1 + i]; 17 } 18 i = 0; 19 j = 0; 20 k = l; 21 //从小到大排序 22 while(i < n1 && j < n2){ 23 if(L[i] <= R[j]){ 24 arr[k] = L[i]; 25 i++; 26 } else{ 27 arr[k] = R[j]; 28 cnt += (n1 - i); 29 j++; 30 } 31 k++; 32 } 33 34 while(i < n1){ 35 arr[k++] = L[i]; 36 i++; 37 } 38 39 while(j < n2){ 40 arr[k++] = R[j]; 41 j++; 42 } 43 44 return cnt; 45 46 } 47 48 long long MergeSortAndCount(int arr[], int l, int r){ 49 long long cnt = 0, cnt1, cnt2, cnt3; 50 if(l >= r) 51 return 0; 52 else { 53 int middle = l + (r - l) / 2; 54 cnt1 = MergeSortAndCount(arr, l, middle); 55 cnt2 = MergeSortAndCount(arr, middle + 1, r); 56 cnt3 = mergeAndCount(arr, l, middle, r); 57 } 58 return cnt1 + cnt2 + cnt3; 59 } 60 61 int main(){ 62 int n; 63 cin >> n; 64 int *arr = new int [n]; 65 for(int i = 0; i < n; i++) 66 cin >> arr[i]; 67 cout << MergeSortAndCount(arr, 0, n - 1) << endl; 68 return 0; 69 }
越努力,越幸运