LeetCode_NO493_Reverse Pairs 解题报告

参考文章:

1.493. Reverse Pairs [Leetcode] [Based on Merge-Sort] [java]

https://blog.csdn.net/gxx_977/article/details/82557881

 

2.分治求逆序对算法

https://blog.csdn.net/fenggla/article/details/54809957

 

 

     最近博主面了 头条系 的公司,面试中有问道这道题。当时思路比较混乱, 想用记忆化去做优化,结果 N^2 的暴力解法也写错了。。。,惭愧。

     现在我整理下如下2种方法的解法,代码不是最优,但是非常适合新手观摩,,,

1.暴力法

2.分治法 (归并排序 + 分治求解)

 

原题如下;

给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对

你需要返回给定数组中的重要翻转对的数量。

示例 1:

输入: [1,3,2,3,1]
输出: 2

示例 2:

输入: [2,4,3,5,1]
输出: 3

注意:

  1. 给定数组的长度不会超过50000
  2. 输入数组中的所有数字都在32位整数的表示范围内。

 

1.暴力法

    暴力法其实比较好理解,就是每次都与之前的记录比较。如果是逆序对,逆序对的总和 + 1 , 整体思路上没有难点,不做细致解答。

代码如下:

 

    public int reversePairs2(int[] nums) {

        if (nums == null || nums.length == 0) {
            return 0;
        }

        int sum = 0;

        int[] memory = new int[nums.length];

        for (int i = nums.length - 1; i >= 0; i--) {
            for (int j = nums.length - 1; i < j; j--) {
                if ((long) nums[i] > 2 * (long) nums[j]) {
                    sum++;
                }
            }
        }

        return sum;
    }

 

 

2.分治法 (归并排序 + 分治求解)

 

思路:

首先这个问题,我们可以拆解为如下问题,

如果该序列被拆解为 2个序列,那么原序列的逆序对是多少的问题。

本题中分治法的细节如下:对于一个序列,将其分解成两个等大的子序列,称其为左序列和右序列,那么逆序对存在于如下三处:

     1.左序列中的逆序对;

      2.右序列中的逆序对;

      3.由左序列中的元素和右序列中的元素构成的逆序对。

      情况1与情况2是易于解决的,只需递归求解左右序列中的逆序对即可;对于情况3,则涉及到分治法的合并步骤,在这个阶段,我们需要判断左序列中的元素和右序列中的元素构成的逆序对,易于想到对于右序列的每个元素,遍历左序列的所有元素,判断哪些能够构成逆序对。

      然而,这种方法与前述的遍历序列的方法实际上没有多大差别,假设大小为n,那么左右序列的大小分别为n/2,那么遍历的时间则为n/2 * n/2 = n^2 /4, 仍为O(n^2)。所以该合并方法并不能更加高效地求出逆序对。那么该如何合并分治的结果呢?

        我开始观察左右序列存在什么特性。我想到,由于此处是考虑左序列的元素和右序列的元素构成的逆序对,那么,如果左序列预先是排好序的,那么对于右序列的任意一个元素,我只需要找到第一个比该元素大的元素,那么左序列中在该大元素后的所有元素都能与右序列中的目标元素构成逆序对。然而这还不够,遍历左序列寻找第一个大元素仍然是O(n)的。怎么办呢?我回到该想法的实现细节中,如果在每一次递归中,我只保证左序列是排好序的,那么在递归回溯时我就不能保证上层的左序列是排好序的。因此我要在合并步骤中保证合并后的序列是排好序的,似乎有点熟悉?没错,这就是归并排序。顺着该思路往下想,如果左右序列都是排好序的,在合并的过程中,我只需同时从左序列头和右序列头开始遍历两个序列,每次发现左序列的元素比右序列的元素大,就说明该左序列的元素及其后的元素都能与右序列的该元素构成逆序对,那么在逆序对的数量上加上这些元素的数量。遍历一次这样的左右序列的时间是O(n)的,而分解策略是将序列分成两个等大的子序列,分解的次数是logn, 故时间复杂度为O(nlogn)。
 

 

所以按照上面的思路,我们把程序拆解为下面3个部分:

//Step1: 左右子问题求解
//Step2 : 求解左右逆序对 多产生的逆序对 (注 : 求解左右的子问题已经保证左右子序列失有序的)
//Step3 : 归并排序, 合并流程

完整代码如下:

package leetcode.hard;

/**
 * Created by szh on 2019/3/11.
 */
public class NO493_Reverse_Pairs {

    //解法一 : 暴力求解法
    public int reversePairs2(int[] nums) {

        if (nums == null || nums.length == 0) {
            return 0;
        }

        int sum = 0;

        int[] memory = new int[nums.length];

        for (int i = nums.length - 1; i >= 0; i--) {
            for (int j = nums.length - 1; i < j; j--) {
                if ((long) nums[i] > 2 * (long) nums[j]) {
                    sum++;
                }
            }
        }

        return sum;
    }


    //解法二 : 归并
    int tmp[];

    public int reversePairs(int[] nums) {

        if (nums == null || nums.length == 0) {
            return 0;
        }

        tmp = new int[nums.length];

        return reversePairsMerge(nums, 0, nums.length - 1);
    }

    private int reversePairsMerge(int[] nums, int left, int right) {

        if (left >= right) {
            return 0;
        }

        int mid = (left + right) / 2;

        //Step1 左右问题求解
        int sum = reversePairsMerge(nums, left, mid) + reversePairsMerge(nums, mid + 1, right);

        int i = left; // i 为左边索引
        int j = 0;  // j 为右边索引

        //Step2 : 求解左右逆序对
        while (i <= mid) {
            j = mid + 1;
            while (j <= right && nums[i] > (long) nums[j] * 2) {
                j++;
            }
            sum += j - mid - 1;
            i++;
        }

        //Step3 : 归并排序, 合并流程
        //int[] tmp = new int[right - left + 1];

        i = left;
        j = mid + 1;

        int k = 0;

        while (i <= mid && j <= right) {
            if (nums[i] < nums[j]) {
                tmp[k++] = nums[i++];
            } else {
                tmp[k++] = nums[j++];
            }
        }

        while (i <= mid) {
            tmp[k++] = nums[i++];
        }

        while (j <= right) {
            tmp[k++] = nums[j++];
        }

        for (int index = 0; index <= right - left; index++) {
            nums[left + index] = tmp[index];
        }

        return sum;
    }


    public static void main(String[] args) {

        //[1,3,2,3,1]
//        {
//            NO493_Reverse_Pairs tmpObj = new NO493_Reverse_Pairs();
//
//            int result = tmpObj.reversePairs2(new int[]{1, 3, 2, 3, 1});
//            System.out.println(result);
//
//        }
//
//        {
//            NO493_Reverse_Pairs tmpObj = new NO493_Reverse_Pairs();
//
//            int result = tmpObj.reversePairs(new int[]{1, 3, 2, 3, 1});
//            System.out.println(result);
//
//        }

//12,2,1,17,19,10,5,23,7,20,10,17,22,15,9,18,12,12,16,16,17,8,11,19,2,21,5,19,22,9,17,24,8,8,16,5,2,25,1,0,3,24,25,0,11,7,19,0,5,16,17,4,19,20,20,0,14,4,16,15,11,15,20,11,17,13,3,18,12,6,10,25,12,6,18,6,19,19,18,13,21,9,17,1,1,2,10,15,24,24,22,7,10,23,15,9,1,23,22,15,3,16,23,25,8,18,0,5,1,12,9,0,25,0,13,11,22,5,3,13,10,17,14,24,23,1,8,1,21,18,2,16,21,21,5,3,19,8,23,6,6,3,2,4,13,2,4,14,9,17,23,18,4,23,5,13,25,10,9,14,3,9,11,5,14,18,0,10,13,5,19,17,24,25,4,8,16,14,3,24,18,2,17,22,4,11,18,9,9,7,10,4,24,0,7,0,6,15,18,13,14,20,22,17,22,15,17,9,10,17,13,0,22,22,23,2,21,18,6,10,10,15,14,4,4,18,21,15,0,18,14,0,2,24,6,10,1,8,25,20,13,20,13,20,5,21,21,9,19,8,9,9,5,17,18,18,20,5,17,18,3,7,21,6,0,8,3,3,1,11,0,21,6,15,11,10,13,6,7,21,7,1,1,14,15,20,2,8,21,25,19,12,18,16,0,4,10,19,14,23,6,17,2,15,19,4,13,8,14,4,15,21,4,23,20,3,18,0,12,14,14,19,0,21,18,21,17,13,9,20,17,25,17,21,16,22,4,1,13,20,15,9,7,18,18,7,22,8,18,1,13,0,24,8,12,16,1,3,6,23,16,24,5,0,1,25,3,16,9,4,24,1,11,24,9,16,11,0,2,20,16,0,1,6,19,22,12,3,23,21,4,20,1,0,18,24,10,0,12,21,17,23,0,13,1,25,9,19,0,13,21,23,6,24,25,16,9,8,16,2,22,23,3,7,16,25,11,18,19,4,11,1,25,22,9,11,14,9,3,16,8,5,11,12,15,15,19,15,15,7,17,24,18,9,8,20,23,18,17,7,8,19,23,9,13,4,17,23,21,19,11,22,22,9,3,19,23,11,2,23,8,8,21,15,1,25,7,6,14,6,7,11,3,2,11,14,10,24,3,8,10,1,18,4,6,16,12,18,12,6,5,25,24,25,7,12,17,19,15,8,23,7,6,11,6,16,14,15,13,18,5,9,21,24,8,17,25,21,22,19,24,9,9,25,21,6,25,24,3,15,20,19,13,7,13,3,0,11,2,3,23,4,14,13,7,14,3,2,18,6,1,24,19,11,6,22,9,20,3,15,23,14,18,11,11,0,2,14,21,1,12,8,8,22,10,25,20,15,22,15,21,4,19,23,5,20,4,10,17,9,7,8,11,7,10,2,18,5,24,4,16,22,13,0,11,6,19,8,21,23,24,14,19,6,3,1,17,25,22,9,14,12,15,2,24,23,17,3,3,3,6,11,20,11,0,12,17,0,3,12,24,5,13,11,19,5,2,5,12,20,19,23,2,14,23,19,4,6,15,12,2,24,17,18,9,18,4,12,20,17,19,21,16,15,13,0,17,10,23,22,10,8,20,6,4,13,11,0,3,1,5,19,17,23,17,10,10,7,4,1,20,21,23,21,21,25,2,1,8,22,4,10,16,9,15,12,12,7,3,10,14,11,9,0,7,1,1,18,23,16,6,4,20,17,18,20,17,22,8,19,6,8,14,23,14,14,15,3,24,19,16,18,14,3,6,10,8,22,12,6,8,5,3,20,10,15,19,17,8,10,7,22,0,5,19,18,16,22,24,6,18,19,19,21,1,22,14,0,24,1,20,21,7,2,11,13,10,9,7,13,15,22,2,17,4,1,4,22,22,7,18,3,12,12,7,6,20,15,25,8,13,7,5,1,25,12,1,25,16,3,23,25,9,22,4,11,16,21,20,15,17,16,13,14,20,5,23,9,0,6,3,21,2,7,2,22,7,5,8,17,14,17,8,18,21,22,14,8,15,2,10,24,0,10,23,11,16,22,5,5,19,20,14,2,19,3,25,5,10,14,22,3,5,10,20,22,16,17,22,15,23,10,0,21,17,20,3,15,0,13,17,2,10,20,8,24,5,6,19,9,4,25,11,19,10,3,24,0,10,10,9,21,16,25,6,20,11,7,17,20,10,9,22,19,21,7,0,4,11,1,9,18,18,3,1,25,5,1,20,13,2,7,19,10,13,25,3,23,13,5,10,15,11,15,22,9,10,8,18,0

        System.out.println("--------------------------------");
        {
            NO493_Reverse_Pairs tmpObj = new NO493_Reverse_Pairs();

            int result = tmpObj.reversePairs(new int[]{12, 2, 1, 17, 19, 10, 5, 23, 7, 20, 10, 17, 22, 15, 9, 18, 12, 12, 16, 16, 17, 8, 11, 19, 2, 21, 5, 19, 22, 9, 17, 24, 8, 8, 16, 5, 2, 25, 1, 0, 3, 24, 25, 0, 11, 7, 19, 0, 5, 16, 17, 4, 19, 20, 20, 0, 14, 4, 16, 15, 11, 15, 20, 11, 17, 13, 3, 18, 12, 6, 10, 25, 12, 6, 18, 6, 19, 19, 18, 13, 21, 9, 17, 1, 1, 2, 10, 15, 24, 24, 22, 7, 10, 23, 15, 9, 1, 23, 22, 15, 3, 16, 23, 25, 8, 18, 0, 5, 1, 12, 9, 0, 25, 0, 13, 11, 22, 5, 3, 13, 10, 17, 14, 24, 23, 1, 8, 1, 21, 18, 2, 16, 21, 21, 5, 3, 19, 8, 23, 6, 6, 3, 2, 4, 13, 2, 4, 14, 9, 17, 23, 18, 4, 23, 5, 13, 25, 10, 9, 14, 3, 9, 11, 5, 14, 18, 0, 10, 13, 5, 19, 17, 24, 25, 4, 8, 16, 14, 3, 24, 18, 2, 17, 22, 4, 11, 18, 9, 9, 7, 10, 4, 24, 0, 7, 0, 6, 15, 18, 13, 14, 20, 22, 17, 22, 15, 17, 9, 10, 17, 13, 0, 22, 22, 23, 2, 21, 18, 6, 10, 10, 15, 14, 4, 4, 18, 21, 15, 0, 18, 14, 0, 2, 24, 6, 10, 1, 8, 25, 20, 13, 20, 13, 20, 5, 21, 21, 9, 19, 8, 9, 9, 5, 17, 18, 18, 20, 5, 17, 18, 3, 7, 21, 6, 0, 8, 3, 3, 1, 11, 0, 21, 6, 15, 11, 10, 13, 6, 7, 21, 7, 1, 1, 14, 15, 20, 2, 8, 21, 25, 19, 12, 18, 16, 0, 4, 10, 19, 14, 23, 6, 17, 2, 15, 19, 4, 13, 8, 14, 4, 15, 21, 4, 23, 20, 3, 18, 0, 12, 14, 14, 19, 0, 21, 18, 21, 17, 13, 9, 20, 17, 25, 17, 21, 16, 22, 4, 1, 13, 20, 15, 9, 7, 18, 18, 7, 22, 8, 18, 1, 13, 0, 24, 8, 12, 16, 1, 3, 6, 23, 16, 24, 5, 0, 1, 25, 3, 16, 9, 4, 24, 1, 11, 24, 9, 16, 11, 0, 2, 20, 16, 0, 1, 6, 19, 22, 12, 3, 23, 21, 4, 20, 1, 0, 18, 24, 10, 0, 12, 21, 17, 23, 0, 13, 1, 25, 9, 19, 0, 13, 21, 23, 6, 24, 25, 16, 9, 8, 16, 2, 22, 23, 3, 7, 16, 25, 11, 18, 19, 4, 11, 1, 25, 22, 9, 11, 14, 9, 3, 16, 8, 5, 11, 12, 15, 15, 19, 15, 15, 7, 17, 24, 18, 9, 8, 20, 23, 18, 17, 7, 8, 19, 23, 9, 13, 4, 17, 23, 21, 19, 11, 22, 22, 9, 3, 19, 23, 11, 2, 23, 8, 8, 21, 15, 1, 25, 7, 6, 14, 6, 7, 11, 3, 2, 11, 14, 10, 24, 3, 8, 10, 1, 18, 4, 6, 16, 12, 18, 12, 6, 5, 25, 24, 25, 7, 12, 17, 19, 15, 8, 23, 7, 6, 11, 6, 16, 14, 15, 13, 18, 5, 9, 21, 24, 8, 17, 25, 21, 22, 19, 24, 9, 9, 25, 21, 6, 25, 24, 3, 15, 20, 19, 13, 7, 13, 3, 0, 11, 2, 3, 23, 4, 14, 13, 7, 14, 3, 2, 18, 6, 1, 24, 19, 11, 6, 22, 9, 20, 3, 15, 23, 14, 18, 11, 11, 0, 2, 14, 21, 1, 12, 8, 8, 22, 10, 25, 20, 15, 22, 15, 21, 4, 19, 23, 5, 20, 4, 10, 17, 9, 7, 8, 11, 7, 10, 2, 18, 5, 24, 4, 16, 22, 13, 0, 11, 6, 19, 8, 21, 23, 24, 14, 19, 6, 3, 1, 17, 25, 22, 9, 14, 12, 15, 2, 24, 23, 17, 3, 3, 3, 6, 11, 20, 11, 0, 12, 17, 0, 3, 12, 24, 5, 13, 11, 19, 5, 2, 5, 12, 20, 19, 23, 2, 14, 23, 19, 4, 6, 15, 12, 2, 24, 17, 18, 9, 18, 4, 12, 20, 17, 19, 21, 16, 15, 13, 0, 17, 10, 23, 22, 10, 8, 20, 6, 4, 13, 11, 0, 3, 1, 5, 19, 17, 23, 17, 10, 10, 7, 4, 1, 20, 21, 23, 21, 21, 25, 2, 1, 8, 22, 4, 10, 16, 9, 15, 12, 12, 7, 3, 10, 14, 11, 9, 0, 7, 1, 1, 18, 23, 16, 6, 4, 20, 17, 18, 20, 17, 22, 8, 19, 6, 8, 14, 23, 14, 14, 15, 3, 24, 19, 16, 18, 14, 3, 6, 10, 8, 22, 12, 6, 8, 5, 3, 20, 10, 15, 19, 17, 8, 10, 7, 22, 0, 5, 19, 18, 16, 22, 24, 6, 18, 19, 19, 21, 1, 22, 14, 0, 24, 1, 20, 21, 7, 2, 11, 13, 10, 9, 7, 13, 15, 22, 2, 17, 4, 1, 4, 22, 22, 7, 18, 3, 12, 12, 7, 6, 20, 15, 25, 8, 13, 7, 5, 1, 25, 12, 1, 25, 16, 3, 23, 25, 9, 22, 4, 11, 16, 21, 20, 15, 17, 16, 13, 14, 20, 5, 23, 9, 0, 6, 3, 21, 2, 7, 2, 22, 7, 5, 8, 17, 14, 17, 8, 18, 21, 22, 14, 8, 15, 2, 10, 24, 0, 10, 23, 11, 16, 22, 5, 5, 19, 20, 14, 2, 19, 3, 25, 5, 10, 14, 22, 3, 5, 10, 20, 22, 16, 17, 22, 15, 23, 10, 0, 21, 17, 20, 3, 15, 0, 13, 17, 2, 10, 20, 8, 24, 5, 6, 19, 9, 4, 25, 11, 19, 10, 3, 24, 0, 10, 10, 9, 21, 16, 25, 6, 20, 11, 7, 17, 20, 10, 9, 22, 19, 21, 7, 0, 4, 11, 1, 9, 18, 18, 3, 1, 25, 5, 1, 20, 13, 2, 7, 19, 10, 13, 25, 3, 23, 13, 5, 10, 15, 11, 15, 22, 9, 10, 8, 18, 0
            });
            System.out.println(result);

        }
    }


}

 

执行时间:

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值