逆序数问题

题目内容:

 设a1, a2,…, an是集合{1, 2, …, n}的一个排列,如果i<j且ai>aj,则序偶(ai, aj)称为该排列的一个逆序。例如,2, 3, 1有两个逆序:(3, 1)和(2, 1)。设计算法统计给定排列中含有逆序的个数。

输入格式:

   第一行输入集合中元素个数n,第二行输入n个集合元素

输出格式:

  含有逆序的个数

输入样例:

3

2 3 1

输出样例:

2

解题思路:

如果采用蛮力法求解,即设置一个count=0变量,将两次for循环嵌套调用,每次发现是逆序数则count++,这样的时间复杂度为O(n^2),当n值过大时,效率不高。

使用分治法求解可以使得时间复杂度降为O(nlogn)。此题使用分治法的核心在于三步:第一步,将集合二分后求前半部分的逆序数。第二步,求集合二分后的后半部分的逆序数。第三分,两个集合之间的逆序数。在第三步即可使用归并法来完成,而核心在于每次求两个集合的逆序数时,这两个集合应该为有序集合,这样将其归并时,可直接求得逆序数。因此在每次调用count_together这个函数时参与在其中的集合应该是有序集合。

代码示例:

#include<iostream>
using namespace std;

//n为左边集合的起点,k为右边集合的起点,m为终点,总共m-n+1个元素
int count_together(int n, int k, int m,int* arr) {
    int i = n, j = k;
    int num = 0;
    int* b;
    b = (int*)malloc((m - n + 1) * sizeof(int));
    int x = 0;
    while(i<k&&j<=m)
    {
        if (arr[i] > arr[j]) 
        {
            b[x] = arr[j];
            x++;
            num = num + k - i;
            j++;
        }
        else 
        {
            b[x] = arr[i];
            x++;
            i++;
        }
    }
    while(i < k)
    {
        b[x] = arr[i];
        i++;
        x++;
    }
    while(j <= m)
    {
        b[x] = arr[j];
        j++;
        x++;
    }
    for (int i = n; i <= m; i++)
        arr[i] = b[i-n];
    return num;
}
//n为起点,k为终点
int count_num(int n, int k, int* arr) {
    if (n >= k)
        return 0;
    int num_1, num_2, num_3;
    int mid = (n + k) / 2;
    num_1 = count_num(n, mid, arr);
    num_2 = count_num(mid + 1, k, arr);
    num_3 = count_together(n, mid + 1, k, arr);
    return num_1 + num_2 + num_3;
}
int main()
{
    int n;
    cin >> n;
    int* arr;
    arr = (int*)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++)
        cin >> arr[i];
    int num = count_num(0,n-1, arr);
    cout << num;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值