在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:归并排序
在归并排序的基础上进行统计,可以发现需要归并的两个区间,如果需要排序则是逆序的,也就是我们需要统计的次数。
官方题解(带视频)
class Solution:
def reversePairs(self, nums: List[int]) -> int:
length = len(nums)
# 辅助数组,传递过去的话,就只申请了一次空间
temp = [0] * length
return self.merger(nums, 0, length-1, temp)
# 归并排序
def merger(self, nums, left, right, temp):
# print(left, right)
if left >= right:
return 0
mid = left + ((right - left) >> 1)
# print(left, right, mid)
cnt_left = self.merger(nums, left, mid, temp)
cnt_right = self.merger(nums, mid+1, right, temp)
# 检测是否需要合并(两个区间是否可以直接有序):
if nums[mid] <= nums[mid+1]:
return cnt_left + cnt_right
# 合并:
temp[left:right+1] = nums[left:right+1] # 复制时不要复制整个数组
i = left
j = mid + 1
k = left
cnt_merger = 0
while i <= mid and j <= right:
if temp[i] <= temp[j]:
nums[k] = temp[i]
k += 1
i += 1
else:
nums[k] = temp[j]
cnt_merger += mid - i + 1
k += 1
j += 1
# 左区间是否全部放入temp:
if i <= mid:
while i <= mid:
nums[k] = temp[i]
k += 1
i += 1
# 右区间是否全部放入temp:
if j <= right:
while j <= right:
nums[k] = temp[j]
k += 1
j += 1
return cnt_left + cnt_right + cnt_merger