剑指offer35_数组中的逆序对_题解
数组中的逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述
题目保证输入的数组中没有的相同的数字输入
[1,2,3,4,5,6,7,0]返回值
7
分析
方案一:归并排序
计算逆序数就发生在排序的过程中,利用了「排序」以后数组的有序性。
思想是「分治算法」,所有的「逆序对」来源于 3 个部分:
- 左边区间的逆序对;
- 右边区间的逆序对;
- 横跨两个区间的逆序对。
代码
/**
1.时间复杂度:O(NlogN)
归并排序的时间复杂度,直接看递归树的结点个数
2.空间复杂度:O(N)
**/
class Solution
{
public:
const int MOD = 1000000007;
int mergeAndCount(vector<int> &data, int left, int mid, int right, vector<int> &temp)
{
for (int i = left; i <= right; i++)
{
temp[i] = data[i];
}
int i = left, j = mid + 1;
int cnt = 0;
for (int k = left; k <= right; k++)
{
//判断是否越界
if (i == mid + 1)
{
data[k] = temp[j];
j++;
}
else if (j == right + 1)
{
data[k] = temp[i];
i++;
}
else if (temp[i] <= temp[j])
{
data[k] = temp[i];
i++;
}
else
{
data[k] = temp[j];
j++;
//在j指向的元素归并回去的时候,计算逆序对的个数
cnt = (cnt + (mid - i + 1)) % MOD;
}
}
return cnt;
}
int reversePairs(vector<int> &data, int left, int right, vector<int> &temp)
{
if (left == right)
{
return 0;
}
int mid = left + (right - left) / 2;
int leftPairs = reversePairs(data, left, mid, temp);
int rightPairs = reversePairs(data, mid + 1, right, temp);
// 如果整个数组已经有序,则无需合并
if (data[mid] <= data[mid + 1])
{
return leftPairs + rightPairs;
}
int crossPairs = mergeAndCount(data, left, mid, right, temp);
return (leftPairs + rightPairs + crossPairs) % MOD;
}
int InversePairs(vector<int> data)
{
int len = data.size();
if (len < 2)
{
return 0;
}
vector<int> copy(data.begin(), data.end());
vector<int> temp(len);
return reversePairs(copy, 0, len - 1, temp);
}
};

浙公网安备 33010602011771号