假设A[1...n]是一个有n个不一样数的数组,若是i<j,且A[i]>A[j],则(i,j)组成一个逆序对,计算数组A中包含的逆序对的数量ios
示例 1:
输入: [7,5,6,4]
输出: 5
思路:暴力求解的时间复杂度为O(n2),而采用归并排序的方法能够将复杂度将为O(nlgn),即递归的对分开的子序列分别计算逆序对,在合并时计算两个子序列之间的逆序对,最终结果为左侧子序列的逆序对数量+右侧子序列的逆序对数量+合并左右两侧子序列获得的逆序对数量。数组
伪码:伪码中数组下标从1开始计算,而不是0优化
MERGE_INVERSIONS(A,left,mid,right) length1=mid-left+1 length2=right-mid //申请两个新数组,长度分别为length1+1和length2+1 //+1是为了存储哨兵位 L[1...length1+1] R[1...length2+1] for i=0 to length1 L[i] = A[left+i] for j=0 to length2 R[j] = A[mid+j] L[length1+1]=MAX R[length2+1]=MAX i=1 j=1 inversions=0 for n=left to right if L[i]<R[j] A[n]=L[i] ++i else A[n]=R[j] inversions=inversions+length1-i+1 ++j return inversions COUNT_INVERSIONS(A,left,right) if right>left mid = (left+right)/2 leftInversions = COUNT_INVERSIONS(A,left,mid) rightInversions=COUNT_INVERSIONS(A,mid+1,right) return MEGRE_INVERSIONS(A,left,mid,right)+leftInversions+rightOnbersions
源码实现1:上述伪码的对应实现,其中为了保证哨兵位大于全部int值,用long long来存储数组spa
#include <iostream> #include <limits.h> using namespace std; int merge_inversions(int A[],int left,int mid,int right) { int result = 0; int length1 = mid-left+1; int length2 = right - mid; long long *L = new long long[length1 + 1](); long long *R = new long long[length2 + 1](); for(int n = 0;n<length1;++n) { L[n] = A[left+n]; } for(int m = 0;m<length2;++m) { R[m] = A[mid+m+1]; } L[length1] = LLONG_MAX; R[length2] = LLONG_MAX; for(int n1=0,n2=0,i = left;i<right+1;++i) { if(L[n1]<=R[n2]) { A[i] = L[n1]; ++n1; } else { A[i] = R[n2]; result = result + length1 - n1; ++n2; } } delete [] L; delete [] R; return result; } int count_inversions(int *A,int left,int right) { if(left<right) { int mid = (left+right)/2; int resultLeft = count_inversions(A,left,mid); int resultRgiht = count_inversions(A,mid+1,right); return merge_inversions(A,left,mid,right) + resultLeft + resultRgiht; } return 0; } int main() { int test[10]{10,9,8,7,6,5,4,3,2,1}; cout<<count_inversions(test,0,sizeof(test)/sizeof(int)-1)<<endl; for(auto n :test) { cout<<n<<ends; } system("pause"); return 0; }
源码实现2:code
#include <iostream> using namespace std; int merge(int *nums,int *data,int left,int mid,int right) { int length1 = mid - left+1; int length2 = right -mid; for(int n = 0;n<length1;++n) { data[n] = nums[left+n]; } for(int m = 0;m<length2;++m) { data[m+length1] = nums[mid+m+1]; } int result = 0; int n1=0,n2=length1; int index = left; while(n1<length1&&n2<length2+length1) //n2的起始值为length1,共有length2个元素,所以终止值为length2+length1 { if(data[n1]<=data[n2]) { nums[index] = data[n1]; ++n1; } else { nums[index] = data[n2]; result = result + length1-n1; ++n2; } ++index; } //将剩余元素放到数组中 while(n1<length1) { nums[index] = data[n1]; ++n1; ++index; } while(n2<length2+length1) { nums[index] = data[n2]; ++n2; ++index; } return result; } int count(int *nums,int *data,int left,int right) { if(right>left) { int mid = (right+left)/2; int leftResult = count(nums,data,left,mid); int rightResult = count(nums,data,mid+1,right); return merge(nums,data,left,mid,right) + leftResult + rightResult; } return 0; } int main() { int nums[10]{10,9,8,7,6,5,4,3,2,1}; int *data = new int[10](); int result = count(nums,data,0,sizeof(nums)/sizeof(int)-1); for(auto n:nums) { cout<<n<<ends; } delete []data; cout<<endl<<"result:"<<result; system("pause"); return 0; }