小和问题and逆序对

小和问题and逆序对

题目描述:

1. 小和问题:

遍历数组,位于元素左边,且比该元素小的元素总和 
比如数组 [2 1 5]    对于2来说,左边没有比它小的,对于1来说也没有,对于5来说,有2和1比它小,所以总和3

2.逆序对:

所谓逆序对就是[4,2],[4,1],[5,1].....,  那么就是左边比右边大,即右边比左边小的元素对对数。
跟小和思路一样,但是是相反的 一个求左边小 一个求右边小

解题思路:

1. 小和问题

利用归并排序的的merge_array。因为小和问题,是位于元素的左边,且比该元素小的,所以统计merge_array的时候前半部分(即左边)的每个位置,后半部分有几个比它大。

即: res += a[p1]*(right-p2+1);

2. 逆序对

同样利用merge_array,但是逆序对统计的是数组的后半部分的每个位置,前半部分有几个比它大。

即   ret += mid-p1 + 1;

两者都是统计  应该要小的半截的每个位置,另一半截有几个比它大。

比如小和要求是左边小的,而逆序对要求的是右边小

ps:统计大的那半截也ok,但是更复杂一点,因为涉及到哪一方提前结束了,还要 res +,额,自己想一想就明白了

小和代码:

int smallsum(int a[],int n){
	if(n<2)
		return 0;
	int *help = new int[n];
	return mergesort(a,0,n-1,help);
}

int mergersort(int a[],int left,int right,int temp[]){
	if(left<=right)
		return 0;
	int mid = left+((right-left)>>1);
	return mergesort(a,left,mid,temp)+mergesort(a,mid+1,right,temp)+merge(a,left,mid,right,temp);  
	//分成3部分,左边内部的小和+右边内部的小和+ 左边对右边的小和 (重点1)
	
}
//求的是左边 对右边的小和,假如两边归并的时候,左边先上(这里左边先上的事件是左边小,
//跟归并还有点不一样,归并为了稳定性,一样的时候也是左边先上)就触发事件,右边一共有right-p2+1个数大于a[p1],也就是有这么多个a【p1】
//(重点2)

//小和统计的是,前半部分的每个位置,后半部分有几个比它大。

int merge(int a[],int left,int mid,int right,int temp[]){
	int p1 = left,p2=mid+1,k=0;
	int res = 0;
	while(p1<=mid && p2<=right){
		if(a[p1]<a[p2]){
			res += a[p1]*(right-p2+1);
			temp[k++]=a[p1++];
		}
		else{
			temp[k++]=a[p2++];
		}
	}
	while(p1<=mid){
		temp[k++]=a[p1++];
	}
	while(p2<=right){
		temp[k++]=a[p2++];
	}
	//当有一方结束的时候,就没有小和了
	for(int i=0;i<k;++i){
		a[left+i]=temp[i];
	}
	return res;
}

逆序对代码:

逆序对 统计的是 数组的后半部分的每个位置,前半部分有几个比它大。
int mergearray(vector<int> &data, vector<int> &help, int l, int mid, int r) {
	int p1 = l, p2 = mid + 1, i = 0;
	long long ret = 0;
	while (p1 <= mid && p2 <= r) {
		if (data[p1] > data[p2]) {
			ret += mid-p1 + 1; // 这一块主要区别
			help[i++] = data[p2++];
		}
		else {
			help[i++] = data[p1++];
		}
	}

	while (p1 <= mid) {
		help[i++] = data[p1++];
	}

	while (p2 <= r) {
		help[i++] = data[p2++];
	}

	for (int k = 0; k < i; ++k) {
		data[l + k] = help[k];
	}
	return ret;
}

int mergesort(vector<int> &data, vector<int> &help, int l, int r) {
	if (l >= r)
		return 0;
	int mid = l + (r - l)/2;
	//cout << mid << endl;
	return mergesort(data, help, l, mid) +
		mergesort(data, help, mid + 1, r) +
		mergearray(data, help, l, mid, r);
}

// 外部接口
int InversePairs(vector<int> & data) {
	int len = data.size();
	if (len<2)
		return 0;
	vector<int> help(len);
	return mergesort(data, help, 0, len - 1) ;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值