考点:归并排序、逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
思路分析
这是一个归并排序的过程,主要考虑合并两个有序序列时,计算逆序对。
逆序对,前面数字大于后面数字,相当于研究右边有多少比左边当前数小。对于两个升序序列,设置两个下标在左右两个有序序列末尾。每次比较两个末尾值,如果前末尾大于后末尾,则前末尾大于后面所有数,即逆序对数为“后面有序当前长度”个。否则不构成逆序对。然后把较大数拷贝到数组末尾,拷贝的这个指针前移。最终要将两个有序序列合并到辅助数组并有序。
这样在递归前,先递归处理左右半段,则左右有序(将有序数组通过地址传参传回),且左右段逆序对可以得到。再计算左右合并过程时产生的逆序对个数。
7>5,1个逆序对,辅助数组[5,7];6>4,1个逆序对,辅助数组[4,6]。57(由辅助数组返回的data值),46,p1指针在7,p2在6,7大于6,2个逆序对,7入辅助数组,p1前移;5<6无逆序对,6入辅助数组,p2前移;5>4,1个逆序对,5入辅助数组。最后4入辅助数组。最终辅助数组[4,5,6,7],逆序对共5对。
核心代码如下:
int i=r;
int p1=m;
int p2=r;
int count=0;
while(p1>=l && p2>=m+1){
count+=data[p1]>data[p2] ? (p2-m):0;
help[i--]=data[p1]>data[p2] ? data[p1--]: data[p2--];
}
while(p1>=l){
help[i--]=data[p1--];
}
while(p2>=m+1){
help[i--]=data[p2--];
}
实现代码
1.完全正确版。将data、help通过地址传参节省空间。递归调用时,help传给data,data传给help,实现交换,将Help赋值给data
class Solution {
public:
int InversePairs(vector<int> data) {
if(data.size()<2)
return 0;
vector<int>help (data.begin(), data.end());
long count=0;
count=(InversePairsCore(data,help,0,data.size()-1));
return count%1000000007;
}
long InversePairsCore(vector<int> &data,vector<int> &help,int l,int r){
if(l==r)
return 0;
int mid=l+((r-l)>>1);
return InversePairsCore(help,data,l,mid)+InversePairsCore(help,data,mid+1,r)
+merge(data,help,l,mid,r);
}
long merge(vector<int> &data,vector<int> &help, int l,int m,int r){
int i=r;
int p1=m;
int p2=r;
long count=0;
while(p1>=l && p2>=m+1){
count+=data[p1]>data[p2] ? (p2-m):0;
help[i--]=data[p1]>data[p2] ? data[p1--]: data[p2--];
}
while(p1>=l){
help[i--]=data[p1--];
}
while(p2>=m+1){
help[i--]=data[p2--];
}
// for(i=0;i<help.size();i++){
// data.push_back(help[i]);
// }
//help.swap(data);
//把help复制给data
//data.assign(help.begin(), help.end());
//help.clear();
return count;
}
};
2.只传data参数,help占空间。最后释放help数组给data;
运行超时,可通过50%测试
class Solution {
public:
int InversePairs(vector<int> data) {
if(data.size()<2)
return 0;
long long count=0;
count=(InversePairsCore(data,0,data.size()-1));
return count%1000000007;
}
long long InversePairsCore(vector<int> &data,int l,int r){
if(l==r)
return 0;
int mid=l+((r-l)>>1);
return InversePairsCore(data,l,mid)+InversePairsCore(data,mid+1,r)
+merge(data,l,mid,r);
}
long long merge(vector<int> &data,int l,int m,int r){
vector<int>help (data.begin(), data.end());
int i=r;
int p1=m;
int p2=r;
int count=0;
while(p1>=l && p2>=m+1){
count+=data[p1]>data[p2] ? (p2-m):0;
help[i--]=data[p1]>data[p2] ? data[p1--]: data[p2--];
}
while(p1>=l){
help[i--]=data[p1--];
}
while(p2>=m+1){
help[i--]=data[p2--];
}
// for(i=0;i<help.size();i++){
// data.push_back(help[i]);
// }
help.swap(data);
//把data赋值为help;
//data.assign(help.begin(), help.end());
//help.clear();
return count;
}
};