数组中的逆序对
题目描述:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对总数P,并将其P对1000000007取模的结果输出。
要求:空间复杂度为O(n),时间复杂度为O(nlogn)。
示例
输入 :[1,2,3,4,5,6,7,0]
输出:7
解题思路
利用暴力方法的时间复杂度为O(n^2),显然不满足要求。
假设存在两个区间[4,3]和[1,2],那么逆序对为(4,1),(4,2),(3,1),(3,2),当两个区间变的有序时,逆序对的结果一样,这就说明区间有序和无序结果是一样的。
但是如果区间有序,当其中一个元素i与元素j构成逆序对时,元素i后面的元素都可以与元素j构成逆序对。
- 划分:将数组划分为两个区间,并进行递归划分,直到区间的大小为1;
- 排序:使用归并排序处理两个区间,在比较元素大小时,统计逆序对;
- 合并:合并两个区间,并累加逆序对。
python代码实现
class Solution:
count = 0
#两个区间合并
def merge(self, left, right):
res = []
m = len(left)
n = len(right)
i = 0
j = 0
while i<m and j<n:
if left[i] <= right[j]:
res.append(left[i])
i += 1
else:
res.append(right[j])
j += 1
self.count += m-i #统计逆序对
res.extend(left[i:])
res.extend(right[j:])
return res
# 归并排序
def mergeSort(self,array):
n = len(array)
#当区间为1时,开始归并
if n<=1:
return array,0
mid = n//2
left,left_n = self.mergeSort(array[:mid])
right,right_n = self.mergeSort(array[mid:])
res = self.merge(left,right)
return res,left_n+right_n
def reversePairs(self, nums):
if len(nums) < 2:
return 0
self.mergeSort(nums)
return self.count
java代码实现
class Solution {
public static int count = 0;
public void merge(int[] array,int low,int mid,int high){
int[] temp = new int[high-low+1];
int i = low;
int j = mid+1;
int k = 0;
while(i<=mid && j<=high){
if(array[i]<=array[j]){
temp[k++] = array[i];
i++;
} else{
temp[k++] = array[j];
j++;
count += (mid+1-i);
}
}
while(i<=mid) temp[k++] = array[i++];
while(j<=high) temp[k++] = array[j++];
for(int l=0;l<temp.length;l++){
array[low+l] = temp[l];
}
}
public void mergeSort(int[] array,int low,int high){
if(low<high){
int mid = (low+high)/2;
this.mergeSort(array,low,mid);
this.mergeSort(array,mid+1,high);
this.merge(array,low,mid,high);
}
}
public int reversePairs(int[] nums) {
if(nums.length<2) return 0;
this.mergeSort(nums,0,nums.length-1);
return count;
}
}