题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入
复制
1,2,3,4,5,6,7,0
输出
复制
7
思路
利用归并排序思想,不断分别递归调用划分一半的函数,将整个数组划分为左右两半,先不断递归划分左边数组至单个元素,逐层返回上级,
注意:
1.右数组起始索引为start + Index + 1
2.牛客已知题干与书上不同,要求%100000007, 需使用long long 类型数?
C++Primer中写道:如果数值超过了int的表示范围,则用long long.(实际应用中,short显得太小,而long和int一般有一样的尺寸)
3.函数传入参数时copy和data互换?
4.归并算法实现使用递归的理解可以参考Python数据结构笔记及视频
代码
class Solution {
public:
int InversePairs(vector<int> data) {
//判断有效性
if(data.empty())
return 0;
int length = data.size();
//创建辅助数组
vector<int> copy;
//拷贝data内元素至copy中
for(int i = 0; i < length; ++i)
copy.push_back(data[i]);
long long totalNum = InversePairsCore(data, copy, 0, length - 1);
return totalNum%1000000007;
}
long long InversePairsCore(vector<int>& data, vector<int>& copy, int start, int end)
{
//划分至只有一个元素
if(start == end)
{
copy[start] = data[start];
return 0;
}
//用游标将数组划分为2
int Index = (end - start) / 2;
long long left = InversePairsCore(copy, data, start, start + Index);
long long right = InversePairsCore(copy, data,start + Index + 1, end);
//辅助数组游标指向末尾
int indexOfCopy = end;
//声明两个游标分别指向每个左右数组的末尾元素
int i = start + Index;
int j = end;
//声明变量记录逆序对数量
long long count = 0;
//当左右数组内元素未遍历完
while(i >= start && j >= start + Index + 1)
{
//如果左数组末尾元素大于右数组末尾元素
if(data[i] > data[j])
{
copy[indexOfCopy--] = data[i--];
//此时右数组所有元素都与左数组游标所指元素构成逆序对,数量为右数组元素数量
count += (j - start - Index);
}
//左数组末尾元素小于右数组末尾元素
else
{
//将右数组末尾元素拷贝至辅助数组,并前移两个游标
copy[indexOfCopy--] = data[j--];
}
}
//如右(左)数组已复制完毕,但左(右)数组内还有元素,则复制剩余元素到辅助数组中
//如果右子数组拷贝完毕,则继续拷贝剩余左子数组
for(; i >= start ; --i)
copy[indexOfCopy--] = data[i];
//如果左子数组拷贝完毕,则继续拷贝剩余右子数组
for(; j >= start + Index + 1; --j)
copy[indexOfCopy--] = data[j];
return count + left + right;
}
};