求数组中逆序对的个数

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值