编程语言
首页 > 编程语言> > C/C++编程学习 - 第20周 ⑤ 逆序数

C/C++编程学习 - 第20周 ⑤ 逆序数

作者:互联网

题目链接

题目描述

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。

Input
第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= Ai <= 109

Output
输出逆序数

Sample Input

4
2
4
3
1

Sample Output

4

思路

思路一:归并排序,思路看代码和注释吧。

C++代码:

#include<bits/stdc++.h>
using namespace std;
int g_nCount;
void mergearray(int a[], int first, int mid, int last, int temp[])
{
	int i = first, j = mid + 1, m = mid, n = last, k = 0;
	while(i <= m && j <= n)	//a[i] 前面的数  a[j] 后面的数
	{
		if(a[i] < a[j]) temp[k++] = a[i++];
		else
		{
			temp[k++] = a[j++];	//a[j]和前面每一个数都能组成逆序数对
			g_nCount += m - i + 1;
		}
	}
	while(i <= m)
		temp[k++] = a[i++];
	while(j <= n)
		temp[k++] = a[j++];
	for(i = 0; i < k; i++)
		a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
	if(first < last)
	{
		int mid = (first + last) / 2;
		mergesort(a, first, mid, temp);    //左边有序
		mergesort(a, mid + 1, last, temp); //右边有序
		mergearray(a, first, mid, last, temp); //再将二个有序数列合并
	}
}
bool MergeSort(int a[], int n)
{
	int *p = new int[n];
	if(p == NULL) return false;
	mergesort(a, 0, n - 1, p);
	return true;
}
int a[50005];
int main()
{
	int n;
	while(cin >> n)
	{
		memset(a, 0, sizeof(a));
		for(int i = 0; i < n; i++)
			cin >> a[i];
		g_nCount = 0;
		MergeSort(a, n);
		cout << g_nCount << endl;
	}
	return 0;
}

思路二:树状数组求逆序数。因为树状数组下标是从1开始的,所以用数组存的时候下标也要从1开始。然后给一个数组排序,再二分查找在排序后的数组中的位置。举个例子:2 4 3 1,排序后就是1 2 3 4,然后原数组中第一个元素2在第二个位置,4在第四个位置,然后找逆序就是该位置之后的元素个数,因为已经排好序了嘛,后面的元素肯定比前面的大,如果在该元素出现之前,已经有比它大的元素出现了,那么它就是一个逆序。

C++代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50005;
int bit[maxn], n, a[maxn], b[maxn];
int lowbit(int x)
{
    return (x & -x);
}
int sum(int i)
{
    int s = 0;
    while(i > 0)
    {
        s += bit[i];
        i -= lowbit(i);
    }
    return s;
}
void add(int i, int x)
{
    while(i <= n)
    {
        bit[i] += x;
        i += lowbit(i);
    }
}
void init()
{
    memset(bit, 0, sizeof(bit));
    memset(a, 0, sizeof(a));
    memset(b, 0, sizeof(b));
}
int main()
{
    while(scanf("%d", &n) == 1)
    {
        init();
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            b[i] = a[i];
        }
        sort(a + 1, a + n + 1);
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            int pos = lower_bound(a + 1, a + n + 1, b[i]) - a;
            add(pos, 1);
            ans += sum(n) - sum(pos);
        }
        printf("%d\n", ans);
    }
    return 0;
}

标签:last,temp,int,mid,C++,20,first,序数
来源: https://blog.csdn.net/qq_44826711/article/details/113550463