逆序对
在一个序列中,有i<j,且a[i]>a[j],我们称这对数为逆序对。
一个序列的逆序对的数量即为序列的逆序数。
归并排序
归并排序用到了分治的思想。将大问题化成小问题在进行合并。
例:
如上图,我们在回溯的时候可以合并两个子区间来达到排序的效果。
如:[0,1]和[2,2]这两个区间合并,我们这里使用了一个临时数组在存合并之后的序列。合并完在用临时数组给原序列赋值。
void Merge_sort(vector<int> &data, int l, int r, int &ans)
{
if(l >= r)
return ;
int m = (l + r) / 2;
Merge_sort(data, l, m, ans);//递归左边
Merge_sort(data, m + 1, r, ans);//递归右边
int left = l, right = m + 1;
vector <int> vv;//临时数组
while(left <= m || right <= r)
{
if(left > m)//左边区间没有数了
{
vv.push_back(data[right ++]);
continue;
}
if(right > r)//右边区间没有数了
{
vv.push_back(data[left ++]);
continue;
}
if(data[left] <= data[right])//小的先放入临时数组
{
vv.push_back(data[left ++]);
}
else
{
ans = (m - left + 1 + ans) % 1000000007;//求逆序数
vv.push_back(data[right ++]);
}
}
for(int i = l, j = 0; i <= r; i ++, j ++)//将临时数组赋值给原数组
data[i] = vv[j];
}
归并排序与逆序数分析
上面代码中有:ans = (m - left + 1 + ans) % 1000000007
不考虑取模也就是:ans += m - left + 1
这是在当data[left] > data[right]时进行的。
也就是 左边的一个数大于右边的一个数。很明显满足逆序对的定义。
由于回溯之后每个子区间是有序的。所以left后面的数也大于data[left]。
那么有多少个这样的数呢。是(m - left + 1)个。
所以提供了(m - left + 1)个逆序对。