问题描述
Recall the problem of finding the number of inversions. As in the text, we are given a sequence of n numbers a1, …, an, which we assume are all distinct, and we define an inversion to be a pair i < j such that ai > aj.
We motivated the problem of counting inversions as a good measure of how different two orderings are. However, one might feel that this measure is too sensitive. Let’s call a pair a significant inversion if i < j and ai > 2aj. Give an O(n log n) algorithm to count the number of significant inversions between two orderings.
翻译
回顾一下求逆序数对的问题。与正文中一样,我们给定一个由 n 个数 a1, ..., an 组成的序列,假定这些数都是不同的,我们将倒序定义为一对 i < j,使得 ai > aj。
我们提出逆序数对计数问题的动机,是为了很好地衡量两个排序的不同程度。然而,我们可能会觉得这种测量方法过于敏感。让我们把 i < j 且 ai > 2aj 的一对称为显著反转。请给出一个 O(n log n) 算法来计算两个排序之间的重要反转数。
思路
归并排序
代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string>
#include <algorithm>
#include <stdlib.h>
using namespace std;
int res = 0;
const int N = 1e6 + 10;
int ans[N];
int mergeSort(int a[],int l,int r)
{
int mid=l+r>>1,i = l, j = mid+1,k=0;
if (l < r)
{
int mid = l + r >> 1;
mergeSort(a, l, mid);//左边有序
mergeSort(a, mid + 1, r);//右边有序
}
while (i <= mid && j <= r)
{
if (a[i] > a[j] * 2)
{
res += mid - i + 1;
j++;
}
else
i++;
}
i = l, j = mid + 1;
while (i <= mid && j <= r)
{
//if (a[i] <=a[j])
// ans[k++] = a[i++];
//else
//{
// ans[k++] = a[j++];
// res += mid - i+1 ;//普通逆序数对
//}
if (a[i] <=a[j])
{
ans[k++] = a[i++];
}
else
{
ans[k++] = a[j++];
}
}
while (i <= mid)
ans[k++] = a[i++];
while (j <= r)
ans[k++] = a[j++];
//不用对原数组进行排序
for (int i = l, j = 0; i <=r; i++, j++)
a[i] = ans[j];
return res;
}
int main()
{
int n;
cin >> n;
int a[N];
for (int i = 0; i < n; i++)
cin >> a[i];
mergeSort(a, 0, n-1);
cout << "The arr is :" << endl;
for (int i =0; i<n;i++)
cout << a[i]<<" ";
cout << endl<<"The number of new inversion is "<<res << endl;
return 0;
}
测试案例
运行结果
时间复杂度分析
nlogn
速记
while (i <= mid && j <= r)
{
if (a[i] > a[j] * 2)
{
res += mid - i + 1;
j++;
}
else
i++;
}
i=l,j=mid+1;
核心:归并排序中的内容