算法-逆序对

    昨日在hihoCoder看到一题有关逆序对的赛题,题目大概是某个游戏中玩家拥有N艘船只,这些船只等级和火力并不挂钩,也就是说等级高的船只火力并不一定高。所以会存在A船比B船等级高,但是A船火力却低于B船这样的情况。现在将按照等级高低的顺序给出所有船的火力值,请你计算出一共有多少对船满足上面提到的这种情况。

输入

第1行:1个整数N。N表示舰船数量, 1≤N≤100,000

第2行:N个整数,第i个数表示等级第i低的船的火力值a[i],1≤a[i]≤2^31-1。

输出

第1行:一个整数,表示有多少对船满足“A船比B船等级高,但是A船火力低于B船”

样例输入

10
1559614248 709366232 500801802 128741032 1669935692 1993231896 369000208 381379206 962247088 237855491
样例输出
27

用通俗的话来讲,这道赛题就是说给定一个数组A[n],然后找出其中所有的逆序对的个数。最简单的方法就是从头开始遍历,然后每到一个数在和后面所有的数进行对比,这样总的时间复杂度是o(n^2),显然这不能满足高效的要求。仔细想来曾经在剑指offer上看过类似的题目,然后突然豁然开朗,用归并法!下面就开始着手了:

#include <iostream>
using namespace std;

int ReversePairs(int* arr,int n);
int ReversePairCore(int* arr,int* copy,int start,int end);
int main()
{
	int n;
	int a[100000];
	while(cin>>n)
	{
		for(int i=0;i<n;i++)
		{
			cin>>a[i];
		}
	    int result=ReversePairs(a,n);
    	cout<<result<<endl;
	}
	return 0;
}

int ReversePairs(int* arr,int n)
{
	if(arr == NULL || n < 0)
		return 0;
	int* copy=new int[n];
	for(int i=0;i<n;i++)
	{
		copy[i]=arr[i];
	}
	int count=ReversePairCore(arr,copy,0,n-1);

	delete [] copy;
	return count;
}

int ReversePairCore(int* arr,int* copy,int start,int end)
{
	if(start==end)
	{
		copy[end]=arr[end];
		return 0;
	}
	int length=(end-start)/2;
	int left=ReversePairCore(copy,arr,start,start+length);
	int right=ReversePairCore(copy,arr,start+length+1,end);

	int i=start+length;
	int j=end;
	int count=0;
	int temp=end;
	while(i >= start && j >= start+length+1)
	{
		if(arr[i]>arr[j])
	    {
			copy[temp--]=arr[i--];
			count +=j-length-start;
	    }
		else
		{
			copy[temp--]=arr[j--];
		}
	}
    for(;i>=start;i--)
	{
		copy[temp--]=arr[i];
	}
    for(;j>=start+length+1;j--)
	{
		copy[temp--]=arr[j];
	}

	return left+right+count;
	
}
提交上去的结果却是80/100分,思来想去,怎么也想不出为什么!期初想难道是要数组中的值可能会越界?然后把数组的类型都改为long long int,结果还是不行。后来干脆把所有int都换为long long int,结果通过了!然后大为惊奇,突然发现根结原来在count这个函数返回值上,也就是说,A[N]数组中,1≤N≤100,000,当N=100000,若A[N]已为升序,那么逆序对总个数count=N*(N-1)/2=4999950000>2147483647=2^31-1,越界了!也就是说count必须为long long int才能保证不越界。通过此题,然我很是感慨,对于某些边界条件一定要多加警惕,特别是隐性的边界条件。

 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值