首先來看看原題
微軟2023年筆試題
在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個逆序數對。乙個排列中逆序的總數就稱為這個排列的逆序數。如中,2和1,4和3,4和1,3和1是逆序數對,因此整個陣列的逆序數對個數為4,現在給定一陣列,要求統計出該陣列的逆序數對個數。
計算數列的逆序數對個數最簡單的方便就最從前向後依次統計每個數字與它後面的數字是否能組成逆序數對。**如下:
[cpp]view plain
copy
#include
intmain()
; int
ncount = 0;
inti, j;
for(i = 0; i
for(j = i + 1; j
if(a[i] > a[j])
ncount++;
printf("逆序數對為: %d\n"
, ncount);
}
執行結果如下:
這種方法用到了雙迴圈,時間複雜度為o(n^2),是乙個不太優雅的方法。因此我們嘗試用其它方法來解決。
在《白話經典演算法系列之五歸併排序的實現
》中觀察歸併排序——合併數列(1,3,5)與(2,4)的時候:
1.先取出前面數列中的1。
2.然後取出後面數列中的2,明顯!這個2和前面的3,5都可以組成逆序數對即3和2,5和2都是逆序數對。
3.然後取出前面數列中的3。
4.然後取出後面數列中的4,同理,可知這個4和前面數列中的5可以組成乙個逆序數對。
這樣就完成了逆序數對的統計,歸併排序的時間複雜度是o(n * logn),因此這種從歸併排序到數列的逆序數對的解法的時間複雜度同樣是o(n * logn),下面給出**:
[cpp]view plain
copy
//從歸併排序到數列的逆序數對
#include
intg_ncount;
void
mergearray(
inta,
intfirst,
intmid,
intlast,
inttemp)
} while
(i <= m)
temp[k++] = a[i++];
while
(j <= n)
temp[k++] = a[j++];
for(i = 0; i
a[first + i] = temp[i];
} void
mergesort(
inta,
intfirst,
intlast,
inttemp)
} bool
mergesort(
inta,
intn)
intmain()
; g_ncount = 0;
mergesort(a, maxn);
printf("逆序數對為: %d\n"
, g_ncount);
return
0;
}
執行結果:
好了,介紹到這裡後,相信大家對如何求數列的逆序數對已經有了很好的認識,文章中所用到的「知識遷移」這種方法還是不錯的,值得大家掌握。
逆序對 從插入排序到歸併排序
設a 1.n 是乙個包含n個非負整數的陣列。如果在ia j 則 i,j 就稱為a中的乙個逆序對 inversion a 列出陣列 2,3,8,6,1 的5個逆序。b 如果陣列的元素取自集合 1,2,n 那麼,怎樣的陣列含有最多的逆序對?它包含多少個逆序對?c 插入排序的執行時間與輸入陣列中逆序對的數...
逆序對 從插入排序到歸併排序
設a 1.n 是乙個包含n個非負整數的陣列。如果在ia j 則 i,j 就稱為a中的乙個逆序對 inversion a 列出陣列 2,3,8,6,1 的5個逆序。b 如果陣列的元素取自集合 1,2,n 那麼,怎樣的陣列含有最多的逆序對?它包含多少個逆序對?c 插入排序的執行時間與輸入陣列中逆序對的數...
歸併排序 逆序數
對於數列a,將其二分地拆分為b,c 先將b,c分別排序好,再合併b,c即為總的排序,不過在合併的過程中我們可以算出逆序數哦。其原理網上很多,我這裡不再贅述,只給出實現 include include define ll long long using namespace std ll mergeso...