求数组的逆序对个数【先离散化】

参考资料:http://poj.org/problem?id=2299 原题是求数列逆序数对的个数。

如果数组数据范围很大,而数据数量与之相比小很多,那么直接用输入数据来求逆序数就不值得了,可以进行离散化处理。处理要点是:

1.用一个struct接受数据和一个自定义的序号no,排序时序号也就一起排序了。

2.for遍历数组,no的位置写上i,就完成了离散化。

例如:

struct data

{

    int v;

    int no;

};

原始数据:100,10,1000,1

直接做的话空间复杂度为1000,

先将其读进来:{v=100,no=0},{v=10,no=1},{v=1000,no=2},{v=1,no=3}

再排序:{v=1,  no=3},  {v=10,  no=1},  {v=100,  no=0},  {v=1000,  no=2}

新开一个长度为4的数组,遍历刚才已排序的数据,a[no=3]=1,  a[no=1]=2,   a[no=0]=3,   a[no=2]=4,

即:{3,2,4,1} 与原始的{100,10,1000,1}大小关系一直,空间代价O(n)。

#include <stdio.h>
#include <stdlib.h>

// 树状数组
int lowbit(int x);
int gsum(int *p, int n, int pos);
void modify(int *p, int n, int pos, int value);

// 离散化
typedef struct datano
{
	int data;
	int no;
}datano;
int cmpdata(const void *p1, const void *p2);

int main()
{
	int m;
	scanf("%d", &m);
	int j = 0;
	while (j < m)
	{
		printf("The %d th test case:\n", j + 1);
		// 1.输入
		int n;
		int *cmdata;
		int *smdata;
		int s = 0;
		int i = 0;
		datano *input;
		
		scanf("%d", &n);
		input = (datano*) malloc(sizeof(datano) * n);
		while(i < n)
		{
			scanf("%d", &(input[i].data));
			input[i].no = i;
			i++;
		}
		
		// 2.离散化
		qsort(input, n, sizeof(datano), cmpdata);
		cmdata = (int*)malloc(sizeof(int) * n);
		for (i=0; i<n; i++)
		{
			cmdata[input[i].no] = i + 1;
		}
		printf("离散化结果:\t(");
		for (i=0; i<n; i++)
			printf("%d,", input[i].data);
		printf(") -> (");
		for (i=0; i<n; i++)
			printf("%d,", cmdata[i]);
		printf(")\n");
		free(input);
		
		// 3.计算
		smdata = (int*)malloc(sizeof(int) * (n+1));
		for (i=0; i<n+1; i++)
			smdata[i] = 0;
		for (i=0; i<n; i++)
		{
			modify(smdata, n, cmdata[i], 1);
			s += (i + 1 - gsum(smdata, n, cmdata[i]) );
		}
		free(cmdata);
		free(smdata);
		printf("total: \t\t%d inverse pair(s)\n", s);
		j++;
	}
	return 0;
}



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

int gsum(int *p, int n, int pos)
{
	int s = 0;
	int i;
	for (i = pos; i>=1; i -= lowbit(i) )
		s += p[i];
	return s;
}

void modify(int *p, int n, int pos, int value)
{
	int i;
	for (i = pos; i<=n; i += lowbit(i) )
		p[i] += value;
}

int cmpdata(const void *p1, const void *p2)
{
	datano *dp1 = (datano *)p1;
	datano *dp2 = (datano *)p2;
	return dp1->data - dp2->data;
}

input:

4
4
100 10 1 1000
7
1 900 10000 20 -9999 10 100
10 
1 2 3 4 5 6 7 8 9 10
4
9 7 4 2

output:

The 1 th test case:
离散化结果:	(1,10,100,1000,) -> (3,2,1,4,)
total: 		3 inverse pair(s)
The 2 th test case:
离散化结果:	(-9999,1,10,20,100,900,10000,) -> (2,6,7,4,1,3,5,)
total: 		11 inverse pair(s)
The 3 th test case:
离散化结果:	(1,2,3,4,5,6,7,8,9,10,) -> (1,2,3,4,5,6,7,8,9,10,)
total: 		0 inverse pair(s)
The 4 th test case:
离散化结果:	(2,4,7,9,) -> (4,3,2,1,)
total: 		6 inverse pair(s)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值