剑指offer51-数组中的逆序对

原题(来源Leetcode)

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:

输入: [7,5,6,4] 输出: 5

限制:

0 <= 数组长度 <= 50000

解法

思想

暴力:双重循环检查,leetcode中超时

分治思想:使用归并排序的算法,每次给左右两个数组合并的时候,若右边数组中指向的元素小于左边数组指向的元素,则也小于左边数组指向的元素后面的任何一个元素(归并排序合并的时候左右两个数组都是有序的),则此时加上左边数组剩余的元素个数即可。

代码

归并排序大复习,这里提供两种写法:

下面是归并排序较简单的写法,就是每次将数组均分成两个子数组,分到不能再分的时候开始合并相邻的两个子数组。这种写法递归中会创建新数组并拷贝,因此时间成本会略高些。

class Solution {
    int count;//全局变量计数
    public int reversePairs(int[] nums) {
        MergeSort(nums);
        return count;
    }
    public int[] MergeSort(int[] array) {
        if (array.length < 2) return array;
        int mid = array.length / 2;
        int[] left = Arrays.copyOfRange(array, 0, mid);
        int[] right = Arrays.copyOfRange(array, mid, array.length);
        return merge(MergeSort(left), MergeSort(right));
    }
    public int[] merge(int[] left, int[] right) {
        int[] result = new int[left.length + right.length];
        for (int index = 0, i = 0, j = 0; index < result.length; index++) {
            if (i == left.length)
                result[index] = right[j++];
            else if (j == right.length)
                result[index] = left[i++];
            else if (left[i] > right[j]){
                count+=left.length-i;//加上左边数组剩余的元素个数
                result[index] = right[j++];
            }
            else result[index] = left[i++];
        }
        return result;
    }
}

下面是一种递归过程中不用创建数组的归并排序写法,只使用两个和原数组相同大小的数组来回交换数据(做对方的缓存),在局部上操作,时间成本会比上面创建数组的方法更低些,但是是一个量级的,在leetcode中能取得更好的成绩:

class Solution {
    public int reversePairs(int[] nums) {
        int[] temp = nums.clone();//创建一个和原数组相同大小的数组
        return MergeSort(nums, temp, 0, nums.length - 1);
    }

    //[start,end]确定一个数组范围,即递归中要排序的范围,返回值为合并过程中的计数
    private int MergeSort(int[] nums, int[] temp, int start, int end) {
        if (start >= end) return 0;
        int mid = (start + end)/2;
        int left = MergeSort(temp, nums, start, mid);
        int right = MergeSort(temp, nums, mid + 1, end);

        int count = merge(nums, temp, start, mid+1, end);
        return left + right + count;
    }

    //[left,right)和[right,end]确定数组的两部分,合并temp数组中的这两部分到nums数组
    private int merge(int[] nums, int[] temp, int left, int right, int end) {
        int index = left;
        int leftSize = right;//因为直接使用left和right作为后面使用的双指针,这里保存right原位置作为left指针能移动到的最远处
        int count = 0;//合并过程中计数

        while (index <= end) {
            if (left==leftSize) nums[index] = temp[right++];
            else if (right==end+1) nums[index] = temp[left++];
            else if (temp[left] > temp[right]) {
                count += (leftSize - left);//加上左边部分剩余的元素个数
                nums[index] = temp[right++];
            } else nums[index] = temp[left++];
            index++;
        }

        return count;
    }
}

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e5%89%91%e6%8c%87offer51-%e6%95%b0%e7%bb%84%e4%b8%ad%e7%9a%84%e9%80%86%e5%ba%8f%e5%af%b9/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年4月23日
下一篇 2020年4月24日

相关推荐

  • leetcode559-N叉树的最大深度

    原题 给定一个 N 叉树,找到其最大深度。 最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。 例如,给定一个 3叉树 : 我们应返回其最大深度,3。 说明: 树的深度不会…

    2020年1月20日
    060
  • leetcode263-丑数

    原题 编写一个程序判断给定的数是否为丑数。 丑数就是只包含质因数 2, 3, 5 的正整数。 示例1: 输入: 6 输出: true 解释: 6 = 2 × 3 示例2: 输入: …

    算法 2020年2月6日
    0120
  • leetcode1014-最佳观光组合

    原题 给定正整数数组 A,A[i] 表示第 i 个观光景点的评分,并且两个景点 i 和 j 之间的距离为 j - i。 一对景点(i < j)组成的观光组合的得分为(A[i]…

    算法 2020年6月17日
    01950
  • leetcode117-填充每个节点的下一个右侧节点指针II

    原题 给定一个二叉树 struct Node {   int val;   Node *left;   Node *ri…

    2020年1月14日
    0370
  • 用一个栈实现另一个栈的排序

    原题(来源牛客网) 一个栈中元素的类型为整型,现在想将该栈从顶到底按从大到小的顺序排序,只许申请一个栈。除此之外,可以申请新的变量,但不能申请额外的数据结构。如何完成排序? 解法 …

    算法 2020年4月20日
    02110
  • leetcode75-颜色分类

    原题 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。 此题中,我们使用整数 0、 1 和 2 分…

    算法 2020年4月19日
    0220
  • 'leetcode50-Pow(x,n)'

    原题 实现 pow(x, n) ,即计算 x 的 n 次幂函数。 示例1: 输入: 2.00000, 10 输出: 1024.00000 示例2: 输入: 2.10000, 3 输…

    算法 2020年1月5日
    0190
  • leetcode430-扁平化多级双向链表

    原题 您将获得一个双向链表,除了下一个和前一个指针之外,它还有一个子指针,可能指向单独的双向链表。这些子列表可能有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示…

    2019年12月17日
    0100
  • leetcode378-有序矩阵中第K小的元素

    原题 给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。请注意,它是排序后的第k小元素,而不是第k个元素。 示例: matrix = [ &nbs…

    算法 2020年2月14日
    0430
  • leetcode110-平衡二叉树

    原题 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。 示例 1:  给定二叉树 […

    算法 2020年1月17日
    0170

发表回复

登录后才能评论