標籤:
題目:
在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。
思路:
1、順序掃描
順序掃描整個數組,每掃描到一個數字,就將該數字跟後面的數字比較,如果大於的話,則這兩個數字構成了逆序對。(比較簡單,這裡就不貼出代碼)
時間複雜度:O(n^2)
2、歸併思想
將數組不斷地等分為兩個子數組,然後自下而上地統計兩個子數組各自的逆序對以及合并後的逆序對。
假設兩個子數組左右分別為A,B,長度分為lenA,lenB,子數組已排好序,那麼如何計算逆序對的個數呢?
當pA=lenA-1;pB=lenB-1;A[pA]>A[pB],說明A的最後一個數比B所有的數都大,此時個數為lenB,pA--;如果A[pA]<B[pB],說明左邊的數不一定比右邊的大,pB--;依次計算直至pA或pB為0,這樣就得到了兩個數組合并時的逆序對,再加上左子數組的逆序對和右子數組的逆序對,就等於整個數組的逆序對。
(代碼中巧妙地利用了一個輔助數組來排序,參考下面的代碼)
時間複雜度:O(nlogn)
代碼:
#include <iostream>using namespace std;int InversePairsCore(int *data,int *copy,int start,int end){ if(start==end){ copy[start]=data[start]; return 0; } int length=(end-start)>>1; int left=InversePairsCore(copy,data,start,start+length); int right=InversePairsCore(copy,data,start+length+1,end); int i=start+length; int j=end; int copyIndex=end; int count=0; while(i>=start && j>=start+length+1){ if(data[i]>data[j]){ copy[copyIndex]=data[i]; copyIndex--; i--; count+=j-(start+length); } else{ copy[copyIndex]=data[j]; copyIndex--; j--; } } for(;i>=start;i--) copy[copyIndex--]=data[i]; for(;j>=start+length+1;j--) copy[copyIndex--]=data[j]; return left+right+count;}int InversePairs(int *data,int length){ if(data==NULL || length<=0) return 0; int* copy=new int[length]; for(int i=0;i<length;i++) copy[i]=data[i]; int count=InversePairsCore(data,copy,0,length-1); delete[] copy; return count;}int main(){ int A[]={7,5,6,4}; int length=sizeof(A)/sizeof(A[0]); cout << InversePairs(A,length) << endl; return 0;}線上測試OJ:
http://www.nowcoder.com/books/coding-interviews/96bd6684e04a44eb80e6a68efc0ec6c5?rp=2
AC代碼:
class Solution {public: int InversePairs(vector<int> data) { int length=data.size(); if(length<=1) return 0; int start=0; int end=length-1; int result=InversePairsCore(data,start,end); return result; } int InversePairsCore(vector<int> &data,int start,int end){ if(start>=end) return 0; int mid=start+((end-start)>>1); int left=InversePairsCore(data,start,mid); int right=InversePairsCore(data,mid+1,end); int i=start; int j=mid+1; int count=0; vector<int> tmp; while(i<=mid && j<=end){ if(data[i]>data[j]){ count+=end-j+1; tmp.push_back(data[i]); i++; } else{ tmp.push_back(data[j]); j++; } } while(i<=mid) tmp.push_back(data[i++]); while(j<=end) tmp.push_back(data[j++]); for(int k=start;k<=end;k++) data[k]=tmp[k-start]; return left+count+right; }};
class Solution {public: int InversePairs(vector<int> data) { int length=data.size(); if(length<=0) return 0; vector<int> copy(data.begin(),data.end()); int start=0; int end=length-1; int count=InversePairsCore(data,copy,start,end); return count; } int InversePairsCore(vector<int> &data,vector<int> ©,int start,int end){ if(start==end){ copy[start]=data[start]; return 0; } int length=(end-start)>>1; int left=InversePairsCore(copy,data,start,start+length); int right=InversePairsCore(copy,data,start+length+1,end); int i=start+length; int j=end; int copyIndex=end; int count=0; while(i>=start && j>=start+length+1){ if(data[i]>data[j]){ copy[copyIndex--]=data[i--]; count+=j-(start+length); } else copy[copyIndex--]=data[j--]; } for(;i>=start;i--) copy[copyIndex--]=data[i]; for(;j>=start+length+1;j--) copy[copyIndex--]=data[j]; return left+count+right; }};
(劍指Offer)面試題36:數組中的逆序對