分治法 求 逆序对数 的个数 时间复杂度为O(n*logn)

思路:

分治法 归并排序的过程中,有一步是从左右两个数组中,每次都取出小的那个元素放到tmp[]数组中

右边的数组其实就是原数组中位于右侧的元素。当不取左侧的元素而取右侧的元素时,说明左侧剩下的元素均比右侧的第一个元素大,即均能构成一个逆序对。假设现在左侧剩余n个元素,则逆序对数+n。

另外,如果当所有右侧的元素都取完,但是左侧仍然有元素剩余时,左侧剩余的元素已经在之前的运算中加到了逆序对中,不需要再添加一次

下面给出 归并排序 和 求逆序对数 两份代码:

code1:

归并排序

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int a[20];


void query(int a[], int first, int mid, int last, int tmp[]){
    int i = first, j = mid+1;
    int k = 0;
    while(i <= mid && j <= last){
        if(a[i] < a[j]) tmp[k++] = a[i++];
        else tmp[k++] = a[j++];
    }
    while(i <= mid){
        tmp[k++] = a[i++];
    }
    while(j <= last){
        tmp[k++] = a[j++];
    }
    for(int id = 0; id < k; id++){
        a[first + id] = tmp[id];
    }
}

void merge_sort(int* a, int L, int R, int* tmp){
    if(L < R){
        int M = L + (R-L)/2;
        merge_sort(a,L,M,tmp);
        merge_sort(a,M+1,R,tmp);
        query(a,L,M,R,tmp);
    }
}
int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        scanf("%d",&a[i]);
    }
    int tmp[20];
    merge_sort(a,0,n-1,tmp);
    for(int i = 0; i < n; i++){
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

code2:

求逆序对数:

cnt 表示逆序对数的个数

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int a[20];
int cnt;

void query(int a[], int first, int mid, int last, int tmp[]){
    int i = first, j = mid+1;
    int k = 0;
    while(i <= mid && j <= last){
        if(a[i] <= a[j]) tmp[k++] = a[i++];
        else{
            tmp[k++] = a[j++];
            cnt += mid-i+1;
        }
    }
    while(i <= mid){
        tmp[k++] = a[i++];
    }
    while(j <= last){
        tmp[k++] = a[j++];
    }
    for(int id = 0; id < k; id++){
        a[first + id] = tmp[id];
    }
}

void merge_sort(int* a, int L, int R, int* tmp){
    if(L < R){
        int M = L + (R-L)/2;
        merge_sort(a,L,M,tmp);
        merge_sort(a,M+1,R,tmp);
        query(a,L,M,R,tmp);
    }
}
int main(){
    scanf("%d",&n);
    for(int i = 0; i < n; i++){
        scanf("%d",&a[i]);
    }
    int tmp[20];
    cnt = 0;
    merge_sort(a,0,n-1,tmp);
    for(int i = 0; i < n; i++){
        printf("%d ",a[i]);
    }
    printf("cnt = %d\n",cnt);
    printf("\n");
    return 0;
}

LRJ给的代码不好理解....


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值