lintcode解题笔记:Reverse Pairs

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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值