个人觉得这是剑指最难的一题。
分治partition:
归并merge:
// InversePairs.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<vector>
using namespace std;
//遍历的方法,时间复杂度为O(n^2)
class SolutionTraversal {
public:
int InversePairs(vector<int> data)
{
if (data.size() == 0)
{
return NULL;
}
int sum = 0;
int judge = 0;
for (int i = 0; i < data.size() - 1; i++)
{
if (data[i] > data[i + 1])
{
for (int j = 0; j <= i; j++)
{
if (data[j] > data[i + 1])
{
sum++;
}
}
}
}
return sum % 1000000007;
}
};
//归并思想,时间复杂度为O(nlogn)
class Solution
{
public:
int InversePairs(vector<int> data)
{
if (data.size() <= 0)//鲁棒性
{
return NULL;
}
int arr[200000] = {};//题目size最大为200000
for (int i = 0; i < data.size(); i++)
{
arr[i] = data[i];
}
int low = 0;
int high = data.size() - 1;
long long p = 0;
partition(arr, low, high, p);//归并排序
return p % 1000000007;//从这里取模1000000007可以知道p很大,所以需要long long p
}
void partition(int arr[], int low, int high, long long& p)
{
if (low == high)//分治,递归终止条件
{
return;
}
else
{
int mid = (high + low) / 2;//取中间
partition(arr, low, mid, p);//左分治
partition(arr, mid + 1, high, p);//右分治
merge(arr, low, mid, high, p);//归并,将两个有序序列合并为一个有序序列
}
}
void merge(int arr[], int low, int mid, int high, long long& p)
{
vector<int>temp;
int p1 = low; int p2 = mid + 1;
while (p1 <= mid && p2 <= high)
{
if (arr[p1] <= arr[p2])
{
temp.push_back(arr[p1]);
p1++;
}
else
{
//对于本题,在两个子序列left、right合并过程中,当left中当前元素A大于right中当前元素B时,
//因为right序列已经有序,所以不用比较,A一定大于right序列当前所有剩余元素,其全部可以与A组成逆序对,
//即通过一次比较可到一批逆序对,加速统计过程。
temp.push_back(arr[p2]);
// 与归并排序不同的地方,在merge过程中统计逆序对数
p = p + mid - p1 + 1; //计算p1到mid中的元素个数,即p2的逆序数。因为只有p1到mid中的元素大于p2
p2++;
}
}
while (p1 <= mid)//只剩左边了
{
temp.push_back(arr[p1]);
p1++;
}
while (p2 <= high)//只剩右边了
{
temp.push_back(arr[p2]);
p2++;
}
for (int i = 0; i < temp.size(); i++)
{
arr[low + i] = temp[i];//按照排好的顺序,从low开始插入,十分注意
}
}
};
int main()
{
Solution s;
vector<int> data;
for (int i = 0; i < 100000; i++)
{
int num = rand() % 999999;
data.push_back(num);
}
auto result = s.InversePairs(data);
return 0;
}