我們在進行歸併排序的時候,會對兩個有序數組進行比較。
如果a1 比 b4 大, 那麼b1,b2,b3 都會比a1小。
利用這個邏輯,我們就可以嘗試一次批量獲取所有比a1大的數。
並且,如果我們能夠確認a數組中所有的數字再原數組中的下標比b數組中要小,那麼我們就等於可以批量獲取逆序對的數量了。
如何實現?
我們只需要在普通歸併排序的模板中,合併比較的時候,把左邊數組比右邊數組大的條件加一句
ans += right - rightStartingIndex;
代碼如下:
#include <iostream>
using namespace std;
int ans = 0;
int temp[1000];
int line[1000];
void merge_sort(int left, int right){
if(left == right)return;
int mid = (left + right) / 2;
merge_sort(left, mid);
merge_sort(mid + 1, right);
for(int i = left; i <= right; i++){
temp[i] = line[i];
}
int i1 = left, int i2 = mid + 1;
for(int curr = left; curr <= right; curr++){
if(il == mid + 1){
line[curr] = temp[i2++];
}else if(i2 > right){
line[curr] = temp[i1++];
}else if(temp[i1] <= temp[i2]){
line[curr] = temp[i1++];
}else{
ans += (mid - i1 + 1);
line[curr] = temp[i2++];
}
}
return ;
}
Leetcode 493
雖然同時需要找逆序對,可是這一題把逆序對的定義變成num[i] > 2*num[j], where i < j,
我們只需要在進入歸併前,進行數數就可以了。
記住我們並不可以向上面的代碼那樣數數。
比如這個情況
1 2 3 1 1 2 3
1 2 3 1 | 1 2 3
for 1 2 3 1
1 2 | 3 1 ans += 1
for 1 2 3 : skip
for 1 1 2 3 | 1 2 3
由於2 比 1大 ,1就直接被消掉,然後後面來了3,確沒了1,那就算少了,所以最方便還是把數數放在外面。
class Solution {
private:
int ans = 0;
int temp[60000];
vector<int> line;
public:
int reversePairs(vector<int>& nums) {
line = nums;
merge_sort(0, nums.size() - 1);
return ans;
}
void merge_sort(int left, int right){
if(left == right)return;
int mid = (left + right) / 2;
merge_sort(left, mid);
merge_sort(mid + 1, right);
int g = mid + 1;
for(int k = left; k <= mid; k++){
while(g <= right && long(line[k]) > 2*long(line[g])){
g++;
}
ans += g - mid - 1;
}
for(int i = left; i <= right; i++){
temp[i] = line[i];
}
int i1 = left, i2 = mid + 1;
for(int curr = left; curr <= right; curr++){
if(i1 == mid + 1) line[curr] = temp[i2++];
else if(i2 > right) line[curr] = temp[i1++];
else if(temp[i1] <= temp[i2]) line[curr] = temp[i1++];
else line[curr] = temp[i2++];
}
return;
}
};