532.Reverse Pairs
For an array A, if i < j, and A [i] > A [j], called (A [i], A [j]) is
a reverse pair. return total of reverse pairs in A.Example:
Given A = [2, 4, 1, 3, 5] , (2, 1), (4, 1), (4, 3) are reverse pairs. return 3
也就是说,在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字构成一个逆序对。输入一个数组,要求这个数组中逆序对的个数。
第一反应的解法是顺序扫描整个数组,扫到每一个数都把这个数和它后面的数作比较。但这种解法需要O(n2)的时间复杂度。
我们可以这样考虑,先从最小的单位开始比起,比如比较两个相邻的数字,很容易就得出它们是否是一个逆序对,若是的话,总逆序对个数加一,且将这两个数以正序排好,说明这两个数之间的逆序对个数已经计算完了。
再往上一层,是两个已经排好序的小数组,这两个数组内部的逆序对都已经计算好了,此时要merge这两个数组,比如[2,4]和[1,3],利用归并排序:
- 首先两个数组的指针都指向最后一个数字,4和3,前面的比后面的大,因此存在逆序对,且4肯定比第二个数组中3及3之前的数都要大(因为此时的数组已排好序),那么逆序对就要多了2对。同时将4放入merge数组中,并指向下一个要比较的数2
- 此时比较的两个数是2和3,前面的数比后面的小,不构成一个逆序对。将3放入merge数组中,并指向下一个要比较的数1
- 此时比较2和1,前面的比后面的大,因此构成一个逆序对。将2放入merge数组中。
- 最后将1放入数组中。
通过这个过程,我们合并并排序了这两个数组,变成[1,2,3,4],且在过程中计算出这其中的逆序对共有3对。
通过前面的例子,可以总计出统计逆序对数目的过程:
- 把数组分隔成子数组
- 先统计出子数组内部的逆序对数目
- 再统计两个相邻子数组之间的逆序对数目
- 在统计逆序的过程中,同时对数组进行归并排序。
其实利用到了一个分治法,以小见大。
完整代码:
public class Solution {
/**
* @param A an array
* @return total of reverse pairs
*/
int count = 0;
public long reversePairs(int[] A) {
if(A.length <= 1) return 0;
merge(A,0,A.length-1);
return count;
}
private int[] merge(int[] A,int start,int end){
if(start == end){
int[] sort = new int[1];
sort[0] = A[start];
return sort;
}
int mid = (start + end)/2;
int[] a1 = merge( A,start,mid);
int[] a2 = merge( A,mid+1,end);
int i = a1.length-1;
int j = a2.length-1;
int k = a1.length+a2.length-1;
int[] sort = new int[a1.length+a2.length];
while(i>=0 && j>=0){
if(a1[i]>a2[j] ){
count += (j+1);
sort[k--] = a1[i--];
}else {
sort[k--] = a2[j--];
}
}
while(i>=0){
sort[k--] = a1[i--];
}
while(j>=0){
sort[k--] = a2[j--];
}
return sort;
}
}