首先说一下逆序对的定义,就是在一个数字数组里面,如果后面的数大于前面的数,被称为一个逆序对
例如 3 5 2 4 1 8 7 9
逆序对分别是(5,2)(3,2)(5,4)。。。等等
首先最好理解的一个就是直接暴力遍历一遍就好了
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
int array[8]={3,5,2,4,1,8,7,9};
int sum=0;
for(int i=1;i<8;i++)
{
for(int j=0;j<i;j++)
{
if(array[i]<array[j])
{
sum++;
}
}
}
cout << sum;
return 0;
}
暴力的时间复杂度为O(n^2);
第二就是归并排序求逆序数简单的图式分解简要介绍一下归并排序
回溯过程中进行合并的时候进行归并排序
归并排序求逆序数的算法
#include <stdlib.h>
#include <stdio.h>
int Count;
void Merge(int sourceArr[],int tempArr[], int startIndex, int midIndex, int endIndex)
{
int i = startIndex, j=midIndex+1, k = startIndex;
while(i!=midIndex+1 && j!=endIndex+1)
{
if(sourceArr[i] > sourceArr[j])
{
tempArr[k++] = sourceArr[j++];
Count += midIndex - i + 1;
}
else
tempArr[k++] = sourceArr[i++];
}
while(i != midIndex+1)
tempArr[k++] = sourceArr[i++];
while(j != endIndex+1)
tempArr[k++] = sourceArr[j++];
for(i=startIndex; i<=endIndex; i++)
sourceArr[i] = tempArr[i];
}
//内部使用递归
void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
int midIndex;
if(startIndex < endIndex)//第一个和最后一个,相等的话return,回溯是排序
{
midIndex = (startIndex + endIndex) / 2;
MergeSort(sourceArr, tempArr, startIndex, midIndex);
MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
}
}
int main(int argc, char * argv[])
{
int a[8] = {50, 10, 20, 30, 70, 40, 80, 60};
int i, b[8];//临时备用数组
MergeSort(a, b, 0, 7);
for(i=0; i<8; i++)
printf("%d ", a[i]);
printf("\n");
printf("%d\n",Count);
return 0;
}
归并排序的时间复杂度为O(nlogn),此方法的时间复杂度也是这个
第三种是很常用的树状数组求逆序数
关于树状数组这个东西很神奇,暂时还是理解的不是很透彻,尽量写一下来多理解一下
答题思路:
对于一个序列
50, 10, 20, 30, 70, 40, 80, 60
首先找到他的最大的数,80,将他的位置置1
0 0 0 0 0 0 1 0
前边没有数据,即Count=0;
第二大数 70 位置置 1
0 0 0 0 1 0 1 0
统计其前的数据Count=0;
第三大数60 位置置1
0 0 0 0 1 0 1 1
统计前面的数 Count=2;
。。。。。
树状数组也是一种很神奇的数据结构
关于树状数组的文章 http://www.cppblog.com/Ylemzy/articles/98322.html
关于树状数组的几点说明用法讲解
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 500005;
struct Node
{
int val;
int pos;
};
Node node[N];
int c[N], reflect[N], n;
bool cmp(const Node& a, const Node& b)
{
return a.val < b.val;
}
int lowbit(int x)//对于1位1,2位2,4为4 5,为1 等等,最后一个不为0的数的2的x次方
{
return x & (-x);
}
void update(int x)
{
while (x <= n)
{
c[x] += 1;
x += lowbit(x);
}
}
int getsum(int x)
{
int sum = 0;
while (x > 0)
{
sum += c[x];
x -= lowbit(x);
}
return sum;
}
int main()
{
while (scanf("%d", &n) != EOF && n)
{
for (int i = 1; i <= n; ++i)
{
scanf("%d", &node[i].val);
node[i].pos = i;
}
sort(node + 1, node + n + 1, cmp); //排序
for (int i = 1; i <= n; ++i) reflect[node[i].pos] = i; //离散化
for (int i = 1; i <= n; ++i) c[i] = 0; //初始化树状数组
long long ans = 0;
for (int i = 1; i <= n; ++i)//对原数组进行从第一个往后计算个数
{
update(reflect[i]);//放在该放的位置
ans += i - getsum(reflect[i]);//getsun函数求的是放在他的正常放在其前面的个数
}
printf("%lld\n", ans);
}
return 0;
}