題目:
對於乙個元素個數為n的陣列a,若*a[i] > a[j],且0<= i < j < n,則a[i]和a[j]為乙個逆序對。現在要求給定陣列的逆序對數
解析:
對於這乙個題目,最容易想到的方法即順序掃瞄整個陣列。沒掃瞄到乙個元素,則將該元素與其後面的所有元素進行比較,若後面的元素比該元素大,則找到乙個逆序數。這一過程,對於陣列中位置i處的元素需要與n - i - 1個元素進行比較。所以時間複雜度為o(n^2).
當然對於這個題目可以利用分治法來求解。首先將陣列一分為2,前半部分為a[0~mid],後半部分為a[mid+1, n)。假設我們通過前面的計算,已經獲得了前半部分的子陣列內部的逆序數為left,後半部分子陣列的逆序數為right。那麼現在我們只需要求前半部分子陣列的元素相對後半部分子陣列中元素的逆序數即可,假設這一逆序數為mid。那麼整個陣列的逆序數count = left + mid + right。
由於假設前半部分子陣列和後半部分子陣列均有序,那麼我們可以利用歸併的思想,將這兩個已序子陣列合併為乙個完整的有序陣列。這一過程其實就是歸併排序的思想,其實求陣列逆序數問題,就可以利用歸併排序對陣列進行排序,在歸併的過程中統計陣列的逆序數。統計方式如下圖所示:
假設歸併過程的輸入為(a, begin, mid, end),其中a[bigin, mid]和a[mid+1, end]分別有序。如上圖,初始時設i = begin, j = mid。那麼合併過程的統計逆序數的的過程就如以下**所示:
//b為輔助陣列
while(i <= mid && j <= end)
//if(a[i] <= a[j])
else
//else
}//while
根據歸併排序的思想,則容易知道這種方法的複雜度為o(nlogn),要優於之前的o(n^2)的方法。
完整的**如下所示:
/*
*本檔案包含解決陣列逆序數問題的原始碼
*對於乙個元素個數為n的陣列a,若
*a[i] > a[j],且0<= i < j < n,則a[i]和a[j]為乙個逆序對
*/#include #include #include using namespace std;
/**用於合併陣列a的兩個有序子陣列,並返回這兩個子陣列的逆序對數
*/int merge(int *a, int begin, int mid, int end)
//if(a[i] <= a[j])
else
//else
}//while
while(i <= mid) b[k++] = a[i++];
while(j <= end) b[k++] = a[j++];
for(i = begin, k = 0; i <= end; i++, k++) a[i] = b[k];
return count;
}//merge
/**用於獲取陣列a在begin和end範圍內的逆序對數
*/int getinversionpaircount(int *a, int begin, int end)
//getinversionpaircount
int main()
//for
int count = getinversionpaircount(a, 0, n-1);
cout << count << endl;
}//while
delete buffer;
}//main
求陣列逆序對
在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數p。並將p對1000000007取模的結果輸出。即輸出p 1000000007 題目保證輸入的陣列中沒有的相同的數字 資料範圍 對於 50的資料,size 10 4 對於 75的...
求陣列逆序對
思路 類似歸併排序演算法,在合併已經有序的相鄰子陣列的時候,計算前面陣列相對於後面陣列的逆序對數,整個遞迴過程可以算出所有逆序對 include void merge int a,int front,int middle,int end,int count else if j end while j...
求陣列中的逆序對數目(POJ1007)
這個題真心寫醜了,不過當做練習還是很不錯的。思想就是利用歸併排序的辦法,先計算左右兩個子陣列的逆序對數目,把他們加起來。然後用兩個指標指向子陣列的頭,如果前面的子陣列目前元素較大,就把後面子陣列的頭部元素插入結果陣列 否則,前面的元素應該進入結果陣列了,此時,結果陣列裡的後面子陣列元素個數即為此元素...