乙個數列,如果左邊的數大,右邊的數小,則稱這兩個數字乙個逆序對。
求出乙個數列中有多少個逆序對。
利用歸併排序的過程完成求逆序對問題。
已知歸併過程如下:
1、首先劃分劃分劃分,一直劃分到不能劃分,即每個組都只有乙個數值。
2、然後合併,合併的過程就是每個二劃分排序的過程。
3、在合併的時候,開闢乙個輔助陣列,其大小等於這兩個合併數列的大小。
4、設定兩個指標分別指向每個數列的首部,然後比較得到其中較小的值,並將這個值放入輔助陣列中。然後取出小值的那個數列的指標可以繼續向前走,與另乙個數列的指標所指向的值繼續比較。
5、這樣比較完成後,如果兩個數列中有個數列的數值有剩餘,即其指標沒有走到末尾,則將這個數列直接賦到輔助陣列末尾即可。
6、然後將輔助陣列中的值拷貝回原陣列中剛才合併的那兩個數列的位置上。
下面舉例:
9 12 5 10
合併:設定輔助陣列:
5 (5比9小,5放入陣列中)
5 9 (10比9大,9放入陣列中)
5 9 10 (12比10大,10放入陣列中)
5 9 10 12 (數列2結束,直接將數列1放入輔助陣列末尾,即12放入陣列中)
完成一次合併排序。
下一次,5 9 10 12 可以和 1 8 11 15進行合併排序。
在上面例子中,左邊數列9與5比較時,它是5左邊的數,且比5大,則9、5是乙個逆序對。求已知9所在的數列是有序的,則12定比5也大,12、5也是乙個逆序對。所以在此次合併排序的過程中,5共參與了兩次逆序對。
而由於這是個遞迴的過程,每個數列都是由包含乙個數值開始合併排序的,所以所有數都會遇到其右邊比它小的數,所以這個過程既不會少算也不會多算。
體現在**中,就是當左邊數列中的數p比右邊數列中的數q大時,則p之後的數也會比q大。則直接可以記錄p右邊有x個數即可,有x個就是左邊數列p及其之後有幾個數。count += a[p1] > a[p2] ? (mid - p1 + 1) : 0;
#include
#include
using
namespace
std;
/*2017/11/12
利用歸併排序求逆序對
*/#if 1
int merge(vector
&a, int l, int mid, int r)
while (p1 <= mid)
help[i++] = a[p1++];
while (p2 <= r)
help[i++] = a[p2++];
for (i = 0; i < help.size(); i++)
a[l + i] = help[i];
return count;
}int mergesort(vector
&a, int l, int r)
int smallsum(vector
a)void main()
; cout
<< smallsum(a) << endl;
system("pause");
}#else
#endif
演算法 求乙個陣列中的逆序對數
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數p。並將p對1000000007取模的結果輸出。即輸出p 1000000007 分析 最簡單的解法就是遍歷陣列中的每乙個元素,讓每個元素與後面的元素對比,如果大於則逆序對數cou...
輸出乙個數列的逆序數
1,這個問題演算法導論講歸併排序時,提到過。找到乙個實現 思路還是蠻清晰的。核心 對於兩個有序序列,找逆序對,遍歷一次即可。2,實現 include include using namespace std int inv int data,int n ret j tmp i j data i 不是逆...
求乙個數中1的個數
碰到遇到乙個有趣的題,求乙個數二進位制的表示中1的個數,該題有兩種解法,一種是使用短除法將該數直接轉化為二進位制數,另一種比較巧妙的演算法是使用與運算,原理如下圖所示 依照此種思入有如下演算法 int numberof1 solution3 int i return count 依照短處法的思路 有...