小和问题and逆序对
题目描述:
1. 小和问题:
遍历数组,位于元素左边,且比该元素小的元素总和
比如数组 [2 1 5] 对于2来说,左边没有比它小的,对于1来说也没有,对于5来说,有2和1比它小,所以总和32.逆序对:
所谓逆序对就是[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) ;
}