題目:
在數組中的兩個數字,如果前面一個數字大於后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。
思路:
歸並排序的合並過程。主要是考慮合並兩個有序序列時,計算逆序對數。
對於兩個升序序列,設置兩個下標:兩個有序序列的末尾。每次比較兩個末尾值,如果前末尾大於后末尾值,則有”后序列當前長度“個逆序對;否則不構成逆序對。然后把較大值拷貝到輔助數組的末尾,即最終要將兩個有序序列合並到輔助數組並有序。
這樣,每次在合並前,先遞歸地處理左半段、右半段,則左、右半段有序,且左右半段的逆序對數可得到,再計算左右半段合並時逆序對的個數。
總個數=左個數+右個數+左右合並時的個數
注意:
注意InversePairsCore形參的順序是(data,copy),而遞歸調用時實參是(copy,data)。
要明白遞歸函數InversePairsCore的作用就行了,它是對data的左右半段進行合並,復制到輔助數組copy中有序。
最后,data和copy兩個數組都是有序的。
代碼:
class Solution { public: int InversePairs(vector<int> data) { if(data.size()<=1) return 0; vector<int> copy(data); return InversePairsCore(data,copy,0,data.size()-1); } private: int InversePairsCore(vector<int> &data,vector<int> ©, int begin, int end) {//合並data的兩半段到輔助數組copy中有序 if(begin==end) { copy[end]=data[end]; return 0; } else { int mid=begin+(end-begin)/2; int left=InversePairsCore(copy,data,begin,mid);//使data的左半段有序 int right=InversePairsCore(copy,data,mid+1,end);//使data的右半段有序 int cnt=0; int cpIndex=end; int pre=mid; int post=end; //合並兩個有序段,到copy數組 while(pre>=begin && post>=mid+1) { if(data[pre]>data[post])//每次比較的是兩個有序序列 { cnt=cnt+(post-mid-1+1); copy[cpIndex--]=data[pre]; pre--; } else { copy[cpIndex--]=data[post]; post--; } } for(;pre>=begin;--pre) copy[cpIndex--]=data[pre]; for(;post>=mid+1;--post) copy[cpIndex--]=data[post]; return left+right+cnt; } } };