分治法解决逆序对问题

在这里插入图片描述

直接暴力, O ( N 2 ) O(N^2) O(N2)时间复杂度,必然是超时的,hard 怎么可能让你这么轻松AC 😏,楼主还是愿意试试:
在这里插入图片描述
试了两种方法超时了,还是太笨了,于是不争气的看了题解😩,之前没做过这种题型,可以理解,下次碰到这种可不能错了,这是基于分治法的一种应用,如果熟悉归并排序的,应该是没问题,不熟悉的话,可以跳到这里 归并排序,我们在合并的过程中进行计算,这里官方给了一个视频讲解,(顺便膜拜一下weiwei大佬😊):

《剑指 Offer》 51. 数组中的逆序对


下面给出相应的代码:

class Solution {
    public int reversePairs(int[] nums) {
        int len = nums.length;
        if(len < 2) return 0;
        return reversePairs(nums, 0, len-1, new int[len]);
    }

    private int reversePairs(int[] nums, int left, int right, int[] temp) {
        if(right == left) return 0;
        int mid = left + ((right-left)>>1) ;
        int leftnum = reversePairs(nums, left, mid, temp);
        int rightnum = reversePairs(nums, mid+1, right, temp);
        int midnum = mergersort(nums, left, mid, right, temp);
        return midnum+leftnum+rightnum;
    }

    private int mergersort(int[] nums, int left, int mid, int right, int[] temp) {
        int p = left, q = mid+1, index = left, count = 0;
        while(p <= mid && q <= right){
            if(nums[p] <= nums[q]){
                temp[index++] = nums[p++];
            }else{
                temp[index++] = nums[q++];
                count += mid-p+1;
            }
        }
        while(p <= mid) temp[index++] = nums[p++];
        while(q <= right) temp[index++] = nums[q++];

        for(int i = left; i<=right; i++) nums[i] = temp[i];
        return count;
    }
}

在这里插入图片描述

class Solution {
    public int reversePairs(int[] nums) {
        int len = nums.length;
        if(len < 2) return 0;
        return reversePairs(nums, 0, len-1, new int[len]);
    }

    public int reversePairs(int[] nums, int left, int right, int[] temp){
        if(left >= right) return 0;
        int mid = left + (right-left)/2;
        int leftnum = reversePairs(nums, left, mid, temp);
        int rightnum = reversePairs(nums, mid+1, right, temp);
        int midnum = merge(nums, left, mid, right, temp);
        return midnum+rightnum+leftnum;
    }

    public int merge(int[] nums, int left, int mid, int right, int[] temp){
        int p = left, q = mid+1, count = 0, index = left;
        while(p <= mid && q <= right){
            if(nums[p] > (long)nums[q]*2){
                count+=mid-p+1;
                q++;
            }else
                p++;
        }
        p = left;
        q = mid+1;
        while(p <= mid && q <= right){
            if(nums[p] <= nums[q]){
                temp[index++] = nums[p++];
            }else{
                temp[index++] = nums[q++];
            }
        }
        while(p <= mid) temp[index++] = nums[p++];
        while(q <= right) temp[index++] = nums[q++];
        for(int i = left; i<= right; i++) nums[i] = temp[i];
        return count;
    }
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
分治法逆序对个数c的实现如下: 1. 将数组a分成两个子数组a1和a2,分别对a1和a2递归地求逆序对个数c1和c2,然后合并a1和a2并计算跨越a1和a2的逆序对个数c3。 2. 合并a1和a2时,设置两个指针i和j分别指向a1和a2的起始位置,然后将较小的元素放入新数组b中,并将指针向后移动,直到其中一个子数组遍历完毕。此时,将另一个子数组的剩余元素全部放入b中。 3. 计算跨越a1和a2的逆序对个数c3时,设置两个指针i和j分别指向a1和a2的末尾位置,并将它们向前移动,同时设置一个计数器count用于计算跨越a1和a2的逆序对个数。比较a1[i]和a2[j]的大小,如果a1[i]>a2[j],则说明a2[j]和a1[i+1]到a1[n-1]都构成了逆序对,因为a1[i+1]到a1[n-1]都比a2[j]大,此时将count加上i+1的值,并将a1[i]放入新数组b中,然后将指针i向前移动;否则,将a2[j]放入新数组b中,并将指针j向前移动。 4. 返回c1+c2+c3作为逆序对个数。 代码实现如下: ``` int mergeSort(vector<int>& a, int left, int right) { if (left >= right) return 0; int mid = (left + right) / 2; int c1 = mergeSort(a, left, mid); int c2 = mergeSort(a, mid + 1, right); vector<int> b(right - left + 1); int i = left, j = mid + 1, k = 0, c3 = 0; while (i <= mid && j <= right) { if (a[i] <= a[j]) b[k++] = a[i++]; else { b[k++] = a[j++]; c3 += mid - i + 1; } } while (i <= mid) b[k++] = a[i++]; while (j <= right) b[k++] = a[j++]; for (int i = left; i <= right; i++) a[i] = b[i - left]; return c1 + c2 + c3; } int countInversePairs(vector<int>& nums) { return mergeSort(nums, 0, nums.size() - 1); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值