题目来源:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
思路:
利用归并排序,归并排序在倒数第二步(即最后的合并之前)会得到左右两个已经排序的子数组,从这里可以得到逆序对数量。
逆序对是归并排序的副产物
举例来说,假设一个数组为[3, 4, 1, 2, 7, 6],划分为两组后,经过归并排序,在最后合并前两个子数组分别为:[1, 3, 4]和[2, 6, 7],假设某时刻,指针i指向3,指针j指向2,那么对于2来说就有逆序对mid - i + 1 = 2 - 1 + 1 = 2对(其实就是len(left) - i),因为左边数组是有序的,如果i位置的数大于j位置的数,那么i之后数也肯定大于j位置的数。所以,统计每次归并时的逆序对数就行了。
class Solution(object):
def reversePairs(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
self.cnt = 0
def merge(nums, start, mid, end): # 归并
i = start
j = mid + 1
res = []
while i <= mid and j <= end:
if nums[i] <= nums[j]:
res.append(nums[i])
i += 1
else: # nums[i]>nums[j],则统计当前数组内的逆序对数
self.cnt += mid - i + 1 # mid + 1其实就是左子数组的长度
res.append(nums[j])
j += 1
while i <= mid:
res.append(nums[i])
i += 1
while j <= end:
res.append(nums[j])
j += 1
for i in range(len(res)):
nums[start + i] = res[i] # 更新nums
def mergesort(nums, start, end):
if start >= end:
return
mid = (start + end) // 2
mergesort(nums, start, mid) # 递归,左子数组继续归并
mergesort(nums, mid + 1, end) # 递归,右子数组继续归并
merge(nums, start, mid, end) # 归并
mergesort(nums, 0, len(nums)-1)
return self.cnt
参考: