剑指 Offer 51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

 

示例 1:

输入: [7,5,6,4]
输出: 5

class Solution {
public:
    //利用递归。
    // 将数组分成A[0] ... A[i] ... A[m]    A[m+1]....A[j]....A[n]两个数组,利用归并排序递归分治排序两个数组
    //逆序对数应该=前一半数组中逆序对数+右一半数组中逆序对+归并两部分数组的逆序对数。
    //最主要问题就是,归并两个有序数组过程中的逆序对数怎么算?
    //例如,A[i]与A[j]合并时,如果 A[i] > A[j],那么A[i+1]...A[m]都是大于A[j]的,就会产生(m-i+1)对 
    int reversePairs(vector<int>& nums) {
        int n = nums.size();
        if(n == 0 || n ==1) return 0;
        vector<int> tmp(n,0);
        int res=0;
        mergesort(nums,tmp,0,n-1,res);
        return res;
    }
    //merge的过程将left到right有序重新存入nums.归并nums[left,mid],nums[mid+1,right]
    void merge(vector<int>& nums,vector<int>& tmp,int left,int mid,int right,int& res) {
        int i=left,j=mid+1,k=left;
        for(i=left,j=mid+1;i<=mid&&j<=right;){
            if(nums[i]<=nums[j]){
                tmp[k] = nums[i];
                i++;
            }else{
                tmp[k] = nums[j];
                j++;
                res += (mid-i+1);
            }
            k++;
        }
        //还有未归并完成的
        while(i<=mid){
            tmp[k]=nums[i];
            i++;
            k++;
        }
        while(j<=right){
            tmp[k]=nums[j];
            j++;
            k++;
        }
        //将tmp重新放入nums,那么nums[left,right]即有序了
        for(int i=left;i<=right;i++){
            nums[i] = tmp[i];
        }
        return;
    }
    //归并排序
    void mergesort(vector<int>& nums,vector<int>& tmp,int left,int right,int& res) {
        if(left < right){
            int mid = left+(right-left)/2;
            mergesort(nums,tmp,left,mid,res);
            mergesort(nums,tmp,mid+1,right,res);
            //合并nums[left,mid] nums[mid+1,right]
            merge(nums,tmp,left,mid,right,res);
        }
        return;
    }
};

 

posted on 2020-12-20 16:01  wsw_seu  阅读(120)  评论(0编辑  收藏  举报

导航