1,问题:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
2,想法:
(1),暴力枚举法o(n2)
(2),利用归并的思想,先计算左半边的逆序对数,再计算右半边的逆序对数,再计算合并时的逆序对数,合并的过程中排序。方便上层递归计算。
3,在牛客网上的编码为:
class Solution {
public:
int merge(int* p, int low, int mid, int high)
{
int m = mid - low + 1;
int n = high - mid;
int* temp1 = new int[m];
int* temp2 = new int[n];
int i,j;
int count = 0;
int tempflag = 0;//临时标记值,用来记录当前以i为首的逆序对个数
for (i = 0; i < m; i++)
{
temp1[i] = p[i + low];
}
for (j = 0; j < n; j++)
{
temp2[j] = p[j + mid + 1];
}
int k = low;
//整个算法的难点就在合并这里,看怎么计算count
for (i = 0, j = 0; i < m && j < n;)
{
if (temp1[i] > temp2[j])
{
count++;
p[k] = temp2[j];
tempflag = count;//时刻标记着,记录以当前i为首的逆序对的个数
j++;
k++;
}
else
{
p[k] = temp1[i];
i++;
k++;
//count = count + count;//这里不能是翻倍的增加,会放大
//例子就是6,5,4,3,2,1,应该增加的是以i-1为首的逆序对个数
//在决定是否加tempflag前,应该判断i值是否已经超出
//超出就不再加了,因为这时的i不存在,若加就多算了一次
//例子就是1,2,1,2,1
if (i < m)
{
count = count + tempflag;
}
}
}
if (i < m)
{
p[k] = temp1[i];//以这个i为首的逆序对已经求了,不能再算一次
k++;
for (i = i + 1; i < m; i++)//现在以i为首的逆序对数就是tempflag个
{
p[k] = temp1[i];
//count = count + count;
count = count + tempflag;
k++;
}
}
else if (j < n)
{
for (j; j < n; j++)
{
p[k] = temp2[j];
k++;
}
}
delete temp1;
delete temp2;
return count;
}
int Count(int *p, int low, int high)
{
if (p == NULL || low == high)
{
return 0;
}
int count = 0;
if (low < high)
{
int mid = (low + high)/2;
int leftcount = Count(p, low, mid);
int rightcount = Count(p, mid + 1, high);
int mergecount = merge(p, low, mid, high);
count = leftcount + rightcount + mergecount;
}
return count;
}
int InversePairs(vector<int> data) {
//O(n2),最笨方法
/*if (data.empty())
{
return 0;
}
unsigned int i,j;
int count = 0;
for (i = 0; i < data.size(); i++)
{
for (j = i + 1; j < data.size(); j++)
{
if (data[i] > data[j])
{
count++;
}
}
}
return count;*/
if (data.empty())
{
return 0;
}
unsigned int i;
int m = data.size();
int *temp = new int[m];
for (i = 0; i < m; i++)
{
temp[i] = data[i];
}
return Count(temp, 0, m - 1);
}
};
在利用合并的思想要注意的几点:
(1),怎么尽量少使用辅助空间
(2),在合并的过程中,计算逆序对,需要考虑全面,即将两个有序数组合A(在前)和B(在后)并为一个有序数组的过程中,每次A数组的指针i增加1时,先要考虑这个指针i是否已经超出限制条件,若没有,那以这个指针i所在位置值为首的逆序对,至少都有以i-1所在位置为首的逆序对个数那么多个。而我们需要做的就是记录以当前i所在位置值为首的逆序对的个数。以方便当i增加1时,把握count的变化。