面试训练寻找逆序对

该题第一眼看到 就是从头到尾一个一个的比,然后找逆序对。

方法简单,可惜不行。


思考:

我开始分析的思路是 归并吧。

可是 我想到了 把7.5.6,4分成7,5,和6,4这两个数组求逆序对,至于合并这两个含2个元素的数组就找不到好的解决方法。


看了书才明白,需要将合并后的子数组排序,然后分别在两个排序了的子数组中,进行查找,从最后一个最大元素开始,

当前半部分最大的元素 大于后半部的,那么逆序对,加上后半部的元素总数,保存前半部元素,移动指针。

当前半部的最大元素 小于后半部的,那么逆序对 不变,同时保持后半部最大元素,移动指针


现在先来来跑一下归并的code。

归并可以说是稳定的o(nlogn)的算法,为什么呢,因为都是左边比右边,相等的始终在左边。

#include "stdio.h"
#include "string.h"
#define MAX 1024
#define LARGEST 0x7FFFFFFF
void mSort(int *data,int s,int m,int d)
{
	int left[MAX],right[MAX];
	int i,j,k;
	int leftMax,rightMax;
	for(i=s;i<=m;i++)
	{
		left[i-s]=data[i];
	}
	left[i-s]=LARGEST;
	for(j=m+1;j<=d;j++)
	{
		right[j-m-1]=data[j];
	}
	right[j-m-1]=LARGEST;

	i=0;
	j=0;
	k=s;
	for(k=s;k<=d;k++)
	{
		if(left[i]<=right[j])
			data[k]=left[i++];
		else
			data[k]=right[j++];
	}
}
void mergeSort(int *data,int s,int end)
{
	int num=(s+end)/2;
	if(s<end)
	{
			mergeSort(data,s,num);
			mergeSort(data,num+1,end);
			mSort(data,s,num,end);
	}


}

int main()
{
	int data[] = {5,3,1,7,8,11,4,6,4,5,4};
	int len = sizeof(data)/sizeof(data[0]);
	int index=0;
	mergeSort(data,0,len-1);
	for(index=0;index<len;index++)
		printf("%d ",data[index]);
	return 0;
}

跑完了归并算法,现在需要想想如何在归并算法中,添加逆序对的计算了。

#include "stdio.h"
#include "string.h"
#define MAX 1024
#define LARGEST 0x7FFFFFFF
int globalReverseNum=0;
void mSort(int *data,int s,int m,int d)
{
	int left[MAX],right[MAX];
	int i,j,k;
	int leftMax,rightMax;
	for(i=s;i<=m;i++)
	{
		left[i-s]=data[i];
	}
	left[i-s]=LARGEST;
	for(j=m+1;j<=d;j++)
	{
		right[j-m-1]=data[j];
	}
	right[j-m-1]=LARGEST;

	i=m-s;
	j=d-m-1;
	k=d;
	while(k>=s)
	{
		if(i<0 ||j<0)
			break;
		if(left[i]>right[j])
		{
			globalReverseNum+=(j+1);
			data[k--]=left[i];
			i-=1;
		}
		else
		{
			data[k--]=right[j];
			j-=1;
		}
	}
	for(;j>=0;j--)
		data[k--]=right[j];
	for(;i>=0;i--)
		data[k--]=left[i];
}
void mergeSort(int *data,int s,int end)
{
	int num=(s+end)/2;
	if(s<end)
	{
			mergeSort(data,s,num);
			mergeSort(data,num+1,end);
			mSort(data,s,num,end);
	}


}

int main()
{
	int data[] = {5,3,1};
	int len = sizeof(data)/sizeof(data[0]);
	int index=0;
	mergeSort(data,0,len-1);
	for(index=0;index<len;index++)
		printf("%d ",data[index]);

	printf("\n%d\n",globalReverseNum);
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值