DESC:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
CODE:
JAVA:
class Solution { public int reversePairs(int[] nums) { if (nums == null || nums.length < 2) { return 0; } int[] tempArr = new int[nums.length]; return reversePairs(nums, 0, nums.length-1, tempArr); } public int reversePairs(int[] nums, int left, int right, int[] tempArr) { //递归结束条件 if (left == right) { return 0; } //copy对应区间到临时数组,后面后更改原数组对应区间序列为有序 for (int i=left; i<=right; i++) { tempArr[i] = nums[i]; } //分治,求左半区域,右半区域的逆序数 //注意:[left,right]区域逆序数N=N[left,mid]+N[mid+1,right]+left相对right的CrossrossN(这部分认真想想) int mid = left + (right-left)/2; int leftCount = reversePairs(nums, left, mid, tempArr);//执行后变为有序数组 int rightCount = reversePairs(nums, mid+1, right, tempArr);//执行后变为有序数组 //特殊情况,右半边均大于等于左半边,所以左半边和右半边就组成不了逆序对了,为0 if (nums[mid] <= nums[mid+1]) { return leftCount + rightCount; } //归并计算交叉区域的逆序数(此时左右数组均已有序) int crossCount = crossMerge(nums, left, mid, right, tempArr); return leftCount + rightCount + crossCount; } public int crossMerge(int[] nums, int left, int mid, int right, int[] tempArr) { for (int i=left; i<=right; i++) { tempArr[i] = nums[i]; } int i = left, j = mid+1, count = 0; for (int k=left; k<= right; k++) { if (i == mid+1) { nums[k] = tempArr[j]; j++; } else if (j == right+1) { nums[k] = tempArr[i]; i++; } else if (tempArr[i] <= tempArr[j]) {//注意是<=,不是<,可以看数组想想 nums[k] = tempArr[i]; i++; } else { nums[k] = tempArr[j]; j++; count += (mid - i + 1); } } return count; } }
PYTHON:
class Solution: def reversePairs(self, nums: List[int]) -> int: if nums is None or len(nums)<2: return 0 tempArr = [0] * len(nums) return self.reverse_pairs(nums, 0, len(nums)-1, tempArr) def reverse_pairs(self, nums, left, right, tempArr): if left == right: return 0 mid = left + (right-left)//2 left_count = self.reverse_pairs(nums, left, mid, tempArr) right_count = self.reverse_pairs(nums, mid+1, right, tempArr) if nums[mid] <= nums[mid+1]: return left_count + right_count cross_count = self.cross_pairs(nums, left, mid, right, tempArr) return left_count + right_count + cross_count def cross_pairs(self, nums, left, mid, right, tempArr): for k in range(left, right+1): tempArr[k] = nums[k] i=left j=mid+1 count=0 for k in range(left, right+1): if i == mid+1: nums[k] = tempArr[j] j+=1 elif j == right+1: nums[k] = tempArr[i] i+=1 elif tempArr[i] <= tempArr[j]: nums[k] = tempArr[i] i+=1 else: nums[k] = tempArr[j] j+=1 count += (mid - i + 1) return count
LEETCODE耗时:
NOTES:
1. 归并排序(自底向上求左右有序数组交叉逆序数)
2. 原数组逆序数=左半区域逆序数+右半区域逆序数+左右区域交叉逆序数(通过归并有序数组计算)
3. mid=left+(right-left)/2
4. [left, right], 右闭 right=length-1