面试题36:数组中的逆序对
生活随笔
收集整理的這篇文章主要介紹了
面试题36:数组中的逆序对
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目:在數組中的兩個數字如果前面一個數字大于后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。例如,有一個數組為Array[0..n] 其中有元素a[i],a[j].如果 當i<j時,a[i]>a[j],那么我們就稱(a[i],a[j])為一個逆序對。在數組{7,5,6,4}中一共存在5對逆序對,分別是(7,6),(7,5),(7,4),(6,4),(5,4)。 如果arry[i]>arry[j],因為兩段數組都是有序的,所以arry[i]>arry[mid+1...j],這些都是逆序對,我們統計出的逆序對為j-(mid+1)+1=j-mid。并且將大數arry[i]放入臨時數組temp[]當中,i往前移動 如果arry[i]<arry[j],則將大數arry[j]放入temp[]中,j往前移。
參考文獻
排序算法匯總->歸并排序
解題思路
看到這樣的題目,最簡單的想法就是遍歷每一個元素,讓其與后面的元素對比,如果大于則count++,但是這樣的時間復雜度是o(n2)。這題有更好的解決方法,時間復雜度只需要o(nlogn)。其實這道題目的思路跟歸并排序差不多,求逆序對的過程就是一個求歸并排序的過程,在求出逆序對以后,原數組變得有序,是通過歸并排序得到的。
(1)總體的意思就是將數組分成兩段,首先求段內的逆序對數量,比如下面兩段代碼就是求左右兩端數組段內的逆序對數量
inversions+=InversePairsCore(arry,start,mid,temp);//找左半段的逆序對數目 inversions+=InversePairsCore(arry,mid+1,end,temp);//找右半段的逆序對數目(2)然后求段間的逆序對數量,如下面的代碼
inversions+=MergeArray(arry,start,mid,end,temp);//在找完左右半段逆序對以后兩段數組有序,然后找兩段之間的逆序對。最小的逆序段只有一個元素。(3)然后在求段間逆序對的時候,我們分為arry[start...mid]和arry[mid+1...end],然后設置兩個指針ij分別指向兩段數組的末尾元素,也就是i=mid,j=end。然后比較arry[i]和arry[j],
完整實現代碼
View Code #include<iostream> #include<stdlib.h> using namespace std;void printArray(int arry[],int len) {for(int i=0;i<len;i++)cout<<arry[i]<<" ";cout<<endl; } int MergeArray(int arry[],int start,int mid,int end,int temp[])//數組的歸并操作 {//int leftLen=mid-start+1;//arry[start...mid]左半段長度//int rightLlen=end-mid;//arry[mid+1...end]右半段長度int i=mid;int j=end;int k=0;//臨時數組末尾坐標int count=0;//設定兩個指針ij分別指向兩段有序數組的頭元素,將小的那一個放入到臨時數組中去。while(i>=start&&j>mid){if(arry[i]>arry[j]){temp[k++]=arry[i--];//從臨時數組的最后一個位置開始排序count+=j-mid;//因為arry[mid+1...j...end]是有序的,如果arry[i]>arry[j],那么也大于arry[j]之前的元素,從a[mid+1...j]一共有j-(mid+1)+1=j-mid }else{temp[k++]=arry[j--];}}cout<<"調用MergeArray時的count:"<<count<<endl;while(i>=start)//表示前半段數組中還有元素未放入臨時數組 {temp[k++]=arry[i--];}while(j>mid){temp[k++]=arry[j--];}//將臨時數組中的元素寫回到原數組當中去。for(i=0;i<k;i++)arry[end-i]=temp[i];printArray(arry,8);//輸出進過一次歸并以后的數組,用于理解整體過程return count;}int InversePairsCore(int arry[],int start,int end,int temp[]) {int inversions = 0; if(start<end){int mid=(start+end)/2;inversions+=InversePairsCore(arry,start,mid,temp);//找左半段的逆序對數目inversions+=InversePairsCore(arry,mid+1,end,temp);//找右半段的逆序對數目inversions+=MergeArray(arry,start,mid,end,temp);//在找完左右半段逆序對以后兩段數組有序,然后找兩段之間的逆序對。最小的逆序段只有一個元素。 } return inversions; }int InversePairs(int arry[],int len) {int *temp=new int[len];int count=InversePairsCore(arry,0,len-1,temp);delete[] temp;return count; }void main() {//int arry[]={7,5,6,4};int arry[]={1,3,7,8,2,4,6,5};int len=sizeof(arry)/sizeof(int);//printArray(arry,len);int count=InversePairs(arry,len);//printArray(arry,len);//cout<<count<<endl;system("pause"); }?輸出結果:
調用MergeArray時的count:0 1 3 7 8 2 4 6 5 調用MergeArray時的count:0 1 3 7 8 2 4 6 5 調用MergeArray時的count:0 1 3 7 8 2 4 6 5 調用MergeArray時的count:0 1 3 7 8 2 4 6 5 調用MergeArray時的count:1//這是因為上面65之間有段內的逆序對 1 3 7 8 2 4 5 6 調用MergeArray時的count:0 1 3 7 8 2 4 5 6 調用MergeArray時的count:9//這里全部都是段間的逆序對,(3,2),(7,2),(7,4),(7,5),(7,6),(8,2),(8,4),(8,5),(8,6),一共有九個 1 2 3 4 5 6 7 8 逆序對數量:10?
?
總結
以上是生活随笔為你收集整理的面试题36:数组中的逆序对的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#如何用Graphics画出一幅图表
- 下一篇: onbeforeunload与onunl