题目描述
- 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
算法分析
- 先把数组分割成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对的过程中,还需要对数组进行排序。如果对排序算法很熟悉,我们不难发现这个过程实际上就是归并排序
提交代码(递归方法):
class Solution {
public:
int InversePairs(vector<int> data) {
if (data.empty())
return 0;
vector<int> temp(data.size());
return MSort(data, temp, 0, data.size() - 1);
}
int MSort(vector<int> &data, vector<int> &temp, int start, int end)
{
int left = 0, right = 0, count = 0;
if (start == end)
{
temp[start] = data[start];
}
else
{
int middle = (start + end) / 2;
left = MSort(data, temp, start, middle);
right = MSort(data, temp, middle + 1, end);
count = Merge(data, temp, start, middle, end);
}
return (left + right + count) % 1000000007;
}
int Merge(vector<int> &data, vector<int> &temp, int start, int middle, int end)
{
int i = middle, j = end;
int index = end;
int count = 0;
// 主循环,把数据合并
while (i >= start && j >= middle + 1)
{
if (data[i] > data[j])
{
count += (j - middle);
temp[index--] = data[i--];
if (count >= 1000000007)//数值过大求余
count %= 1000000007;
}
else
temp[index--] = data[j--];
}
// 如果是因为后边子列的数据全部放在临时向量中导致主循环结束
// 则把前面没放完的数据依次放入临时变量中
while (i >= start)
temp[index--] = data[i--];
// 同上处理前面子列数据全部先放入向量中的情况
while (j >= middle + 1)
temp[index--] = data[j--];
// 注意!不能直接用a=tmpArray,因为可能只是复制子列
for (int i = start; i <= end; ++i)
data[i] = temp[i];
return count;
}
};
提交代码(非递归方法):
class Solution {
public:
int InversePairs(vector<int> data) {
if (data.empty())
return 0;
return MSort(data);
}
int MSort(vector<int> &data)
{
int count = 0;
int k = 1;
vector<int> temp(data.size());
while (k < data.size())
{
count += MergePass(data, temp, k);
if (count >= 1000000007)//数值过大求余
count %= 1000000007;
k *= 2;
}
return count;
}
int MergePass(vector<int> &data, vector<int> &temp, int k)
{
int i = 0, count = 0;
int n = data.size();
while (i < (n - 2 * k + 1))
{
count += Merge(data, temp, i, i + k - 1, i + 2 * k - 1);
i += 2 * k;
if (count >= 1000000007)//数值过大求余
count %= 1000000007;
}
if (i < n - k + 1)
{
count += Merge(data, temp, i, i + k - 1, n - 1);
if (count >= 1000000007)//数值过大求余
count %= 1000000007;
}
return count % 1000000007;
}
int Merge(vector<int> &data, vector<int> &temp, int start, int middle, int end)
{
int i = middle, j = end;
int index = end;
int count = 0;
// 主循环,把数据合并
while (i >= start && j >= middle + 1)
{
if (data[i] > data[j])
{
count += (j - middle);
temp[index--] = data[i--];
if (count >= 1000000007)//数值过大求余
count %= 1000000007;
}
else
temp[index--] = data[j--];
}
// 如果是因为后边子列的数据全部放在临时向量中导致主循环结束
// 则把前面没放完的数据依次放入临时变量中
while (i >= start)
temp[index--] = data[i--];
// 同上处理前面子列数据全部先放入向量中的情况
while (j >= middle + 1)
temp[index--] = data[j--];
// 注意!不能直接用a=tmpArray,因为可能只是复制子列
for (int i = start; i <= end; ++i)
data[i] = temp[i];
return count;
}
};
测试代码:
// ====================测试代码====================
void Test(char* testName, vector<int> data, int expected)
{
if (testName != nullptr)
printf("%s begins: ", testName);
Solution s;
if (s.InversePairs(data) == expected)
printf("Passed.\n");
else
printf("Failed.\n");
}
void Test1()
{
vector<int> data = { 1, 2, 3, 4, 7, 6, 5 };
int expected = 3;
Test("Test1", data, expected);
}
// 递减排序数组
void Test2()
{
vector<int> data = { 6, 5, 4, 3, 2, 1 };
int expected = 15;
Test("Test2", data, expected);
}
// 递增排序数组
void Test3()
{
vector<int> data = { 1, 2, 3, 4, 5, 6 };
int expected = 0;
Test("Test3", data, expected);
}
// 数组中只有一个数字
void Test4()
{
vector<int> data = { 1 };
int expected = 0;
Test("Test4", data, expected);
}
// 数组中只有两个数字,递增排序
void Test5()
{
vector<int> data = { 1, 2 };
int expected = 0;
Test("Test5", data, expected);
}
// 数组中只有两个数字,递减排序
void Test6()
{
vector<int> data = { 2, 1 };
int expected = 1;
Test("Test6", data, expected);
}
// 数组中有相等的数字
void Test7()
{
vector<int> data = { 1, 2, 1, 2, 1 };
int expected = 3;
Test("Test7", data, expected);
}
void Test8()
{
int expected = 0;
Test("Test8", vector<int>(), expected);
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
Test8();
return 0;
}