-
题目描述:
- 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
-
输入:
-
每个测试案例包括两行:第一行包含一个整数n,表示数组中的元素个数。其中1 <= n <= 10^5。第二行包含n个整数,每个数组均为int类型。
-
输出:
- 对应每个测试案例,输出一个整数,表示数组中的逆序对的总数。
-
样例输入:
-
4 7 5 6 4
-
样例输出:
-
5
直接的做法是逐个统计,复杂度是N^2,可以利用归并排序的思想,在排序过程中统计逆序对的个数。
时间复杂度依然是 N*Log(N)。 可以从代码中看到,只是比归并排序多了一句代码:cnt += (j-mid);
由于最终个数可能超过int,这里用long long
01 |
//============================================================================ |
02 |
//
Name : 求逆序对.cpp |
03 |
//
Author : coder |
04 |
//
Version : |
05 |
//
Copyright : www.acmerblog.com |
06 |
//
Description : Hello World in C++, Ansi-style |
07 |
//============================================================================ |
08 |
09 |
#include
<iostream> |
10 |
#include
<stdio.h> |
11 |
using namespace std; |
12 |
typedef long long ll; |
13 |
int n,
arr[100010], tmp[100010]; |
14 |
15 |
//归并排序,过程中
统计逆序数 |
16 |
ll
merge( int start, int mid, int end){ |
17 |
ll
cnt = 0; |
18 |
int i
= start, j = mid+1, k = 0; |
19 |
while (
i<=mid && j<= end){ |
20 |
//从小到大排序 |
21 |
if (arr[i]
> arr[j]){ |
22 |
cnt
+= (j-mid); //加上本次的逆序对数 |
23 |
tmp[k++]
= arr[j++]; |
24 |
} else { |
25 |
tmp[k++]
= arr[i++]; |
26 |
} |
27 |
} |
28 |
while (i<=mid)
tmp[k++] = arr[i++]; |
29 |
while (j<=end)
tmp[k++] = arr[j++]; |
30 |
//将临时数组中拍好序的数,重新复制到a中
for ( int i=0;
i<k; i++) arr[start+i] = tmp[i]; |
31 |
return cnt; |
32 |
} |
33 |
ll
inversePairs( int start, int end){ |
34 |
ll
cnt = 0; |
35 |
if (start
< end){ |
36 |
int mid
= (start + end)/2; |
37 |
cnt
+= inversePairs(start, mid); //左半部分
逆序对数量 |
38 |
cnt
+= inversePairs(mid+1, end); //右半部分 |
39 |
cnt
+= merge(start, mid, end); //合并两部分,并计算数量 |
40 |
} |
41 |
return cnt; |
42 |
} |
43 |
int main()
{ |
44 |
//freopen("in.txt",
"r", stdin); |
45 |
while ( scanf ( "%d" ,
&n) != EOF){ |
46 |
for ( int i=0;
i<n; i++) scanf ( "%d" ,
&arr[i]); |
47 |
ll
ans = inversePairs(0, n-1); |
48 |
printf ( "%lld\n" ,ans); |
49 |
} |
50 |
return 0; |
51 |
} |
转自:http://www.acmerblog.com/offer09-2527.html