剑指Offer(51)数组中的逆序对

目录

数组中的逆序对

描述

示例 1

限制

方法:归并排序


数组中的逆序对

描述

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

示例 1

输入

[7,5,6,4]

输出

5

限制

0 <= 数组长度 <= 50000

方法:归并排序

归并排序想必大家都比较熟悉,在归并的过程,就是比较子数组元素的大小,当左边数组当前元素大于右边数组当前元素时,我们认为左边的当前元素至末尾元素右边的当前元素构成了若干个逆序对

合并统计逆序对的步骤如下:

  • 将数组nums[low,high]拷贝到temp数组中
  • 循环合并,设置双指针i,j分别指向左右子数组的首元素(i=low,j=mid+1),其中mid=(low+high)/2
    • 当i=mid+1时,代表左子数组已经合并完,此时仅需要添加右边数组元素temp[j++]
    • 当j=high+1时,代表右子数组已经合并完,此时仅需要添加左边数组元素temp[i++]
    • 否则左右数组均未合并完,需要比较temp[i]temp[j]的大小
      • 当temp[i]<=temp[j]时,添加左边数组元素temp[i++]
      • 当temp[i]>temp[j]时,添加右边数组元素temp[j++];此时构成mid-i+1个逆序对,累加
class Solution {
    int[] nums, temp;
    public int reversePairs(int[] nums) {
        this.nums = nums;
        temp = new int[nums.length];
        return mergeSort(0, nums.length - 1);
    }
    private int mergeSort(int low, int high) {
        if (low >= high) return 0;
        int mid = (low + high) / 2;
        int res = mergeSort(low, mid) + mergeSort(mid + 1, high);//递归划分数组
        for (int i = low; i <= high; i++) {
            temp[i] = nums[i];//复制nums[low,high]的数组到temp中
        }

        int i = low, j = mid + 1;
        for (int k = low; k <= high; k++) {
            if (i == mid + 1) {
                nums[k] = temp[j++];//左边数组合并完了,添加右边数组的元素
            }
            else if (j == high + 1 || temp[i] <= temp[j]) {
                nums[k] = temp[i++];//右边数组合并完了或者左边元素小于右边,添加左边数组的元素
            }
            else {//两边元素都没合并完,且左边元素大于右边,此时构成mid-i+1个逆序对
                nums[k] = temp[j++];
                res += mid - i + 1;
            }
        }
        return res;
    }
}

剑指Offer(51)数组中的逆序对_第1张图片

你可能感兴趣的:(#,剑指offer,逆序对,归并排序)