1.题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。即输出P%1000000007
2.算法描述
本来没有时间限制的话,直接用交换类的排序,比如插入或者冒泡,交换多少次就有多少逆序对。但是这里有时间限制,
只
能
用
O
(
n
l
o
g
n
)
的
算
法
\red{只能用O(nlogn)的算法}
只能用O(nlogn)的算法。
所以就用归并排序呗。
归
并
排
序
是
在
归
并
的
时
候
消
除
逆
序
对
的
,
所
以
我
们
在
归
并
的
时
候
,
要
找
出
每
归
并
一
个
元
素
,
我
们
消
除
了
多
少
个
逆
序
对
。
\red{归并排序是在归并的时候消除逆序对的,所以我们在归并的时候,要找出每归并一个元素,我们消除了多少个逆序对。}
归并排序是在归并的时候消除逆序对的,所以我们在归并的时候,要找出每归并一个元素,我们消除了多少个逆序对。
举例如下:
比如我们现在要归并左子数组
[
2
,
,
6
,
10
,
11
,
15
]
[2,,6,10,11,15 ]
[2,,6,10,11,15]和右子数组
[
1
,
5
,
7
,
8
]
[1,5,7,8 ]
[1,5,7,8],我写的Java代码是从尾部开始归并Python代码是从头部开始归并。以从尾部归并为例。
我们用两个指针
i
,
j
i,j
i,j 分别指向左右子数组的尾部,比较它们指向的数的大小,如果
i
i
i指向的数大于
j
j
j指向的数,那么
i
指
向
的
数
必
然
大
于
j
指
向
的
右
子
数
组
以
及
以
前
的
所
有
数
字
\red{i指向的数必然大于j指向的右子数组以及以前的所有数字}
i指向的数必然大于j指向的右子数组以及以前的所有数字。
在这里
15
>
8
15>8
15>8,那么
15
必
然
大
于
右
子
数
组
所
有
数
\red{15必然大于右子数组所有数}
15必然大于右子数组所有数,那么
对
于
15
有
多
少
的
逆
序
对
\red{对于15有多少的逆序对}
对于15有多少的逆序对?显然就是
j
到
右
子
数
组
头
部
有
多
少
个
元
素
,
就
有
多
少
个
逆
序
对
\red{j到右子数组头部有多少个元素,就有多少个逆序对}
j到右子数组头部有多少个元素,就有多少个逆序对,这里是4。
3.代码描述
3.1.Java代码
#由于Python语言时间的限制 有时可能会通不过
# -*- coding:utf-8 -*-
class Solution:
def InversePairs(self, data):
if not data:
return 0
copy = data[:]
return self.mergeSort(data, copy, 0, len(data)-1) % 1000000007
def mergeSort(self, data, copy, left, right):
if left >= right:
copy[left] = data[left]
return 0
mid = (left + right) / 2
leftCount = self.mergeSort(data, copy, left, mid)
rightCount = self.mergeSort(data, copy, mid+1, right)
count = 0
i = left
j = mid+1
index = left
while i <= mid and j <= right:
if data[i] <= data[j]:
copy[index] = data[i]
i += 1
else:
copy[index] = data[j]
count += mid-i+1
if count>=1000000007:
count %= 1000000007
j += 1
index += 1
while i <= mid:
copy[index] = data[i]
i += 1
index += 1
while j <= right:
copy[index] = data[j]
j += 1
index += 1
data[left:right+1] = copy[left:right+1]
return (count + leftCount + rightCount) % 1000000007