假設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; }