1. 程式人生 > 其它 >求逆序對的兩種方法

求逆序對的兩種方法

1.利用歸併排序求逆序對

注意:此種方法利用了歸併排序每次歸併後的有序性,需要歸併的兩組資料(p1遍歷區間[start,mid]、p2遍歷區間[mid + 1, end])在先前的歸併中已經變得有序,因此這兩組資料在歸併時,只需要看右邊nums[p2]是否小左邊nums[p1],若小於,由於兩組的資料已經變得有序(若大於,則繼續做歸併)因而存在區間[p1, m]中的所有數(即m - p1 + 1個數)與nums[p2]互為逆序對,將這兩組資料合併後,(統計逆序數的在區間[mid + 1, end]中)nums[p2]會被歸併到與之成逆序對的區間中,即消除這個數統計重複的逆序對的可能

#include<iostream>

using namespace std;

const int N = 100010;

int n;
long long cnt;
int nums[N];

void merge(int s, int m, int e){
    
    int tmp[N];
    int p0 = 0, p1 = s, p2 = m + 1;
    
    while(p1 <= m && p2 <= e)
/***************************關鍵程式碼***********************************/    
        if(nums[p1] <= nums[p2]) tmp[p0++] = nums[p1++];
        else{
            tmp[p0++] = nums[p2++];
            cnt += m - p1 + 1;
        }
/***************************關鍵程式碼***********************************/    
    while(p1 <= m) tmp[p0++] = nums[p1++];
    while(p2 <= e) tmp[p0++] = nums[p2++];
    
    for(int i = 0; i < e - s + 1; i++) nums[s + i] = tmp[i];
    
}


void merge_sort(int s, int e){
    int m = s + (e - s) / 2;
    
    if(s < e){
        merge_sort(s, m);
        merge_sort(m + 1, e);
        merge(s, m, e);
    }
    
}

int main()
{
    int n; 
    cin >> n;
    for(int i = 0; i < n; i++) cin >> nums[i];
    
    merge_sort(0, n - 1);
    
    //for(int i = 0; i < n; i++) cout << nums[i] << " ";
    cout << cnt;
    
    return 0;
}

2.用樹狀陣列求逆序對

由於陣列中的每個數是按順序放入樹狀陣列中的,因此找逆序對也就是找在i之前出現的所有數中比第i個數大的所有數的個數(即query(N) - query(i)), 樹狀陣列維護的是原陣列中、第i個數之前的所有數(類似於用了一個hash表來做查詢)

#include<iostream>

using namespace std;

const int N = 1e6 + 10;  //依陣列中值的範圍而定

int tr[N], nums[N];

int lowbit(int x){
	return x & (-x);
}

//add()從下向上加 
void add(int x, int v){
	
	for(int i = x; i <= N; i += lowbit(i)) tr[i] += v;
	
}

//query()從上向下查詢 
int query(int x){
	
	int sum = 0;
	for(int i = x; i > 0; i -= lowbit(i)) sum += tr[i];
	return sum;
	
}

int main()
{
	int n;
	cin >> n;
	for(int i = 0; i < n; i++) cin >> nums[i];
	long long cnt = 0;
	
	//找出在nums[i]前被加入樹狀陣列且比nums[i]大的數 
	
	for(int i = 0; i < n; i++){
		cnt += query(N) - query(nums[i]);
		add(nums[i], 1);
	}
	
	cout << cnt;
	return 0;
}